Multiple images uploading and getting the download urls - Firebase - firebase

I'm currently working on uploading multiple images to firebase and getting the downloadUrl into a list.
_imageList.forEach((element) async {
final StorageReference _ref = FirebaseStorage.instance
.ref()
.child("Users/ads/");
StorageUploadTask uploadTask =
_ref.putFile(element as i.File);
await uploadTask.onComplete;
print("Images uploaded");
String image_links = await _ref.getDownloadURL();
_imageUrls.add(image_links);// _imageUrls is a List
});
and now I wanna assign the _imageUrls into firestore.
Map<String, dynamic> ads = {
'adTitle': widget.title,
'adPrice': widget.price,
'adCategory': widget.dropdownValue,
'adCondition': this.newCondtionVal,
'adDesc': widget.desc,
'user_id': uID,
'imageUrls_List': _imageUrls,//Images goes hear
};
crudObj
.addData(ads)
.then((value) => {
showInSnackBar("dataAdded"),
})
.catchError((e) {
print(e);
});
But the problem is:uploading data to firestore works first(Image upload is not finished yet), So now imageUrls_List slot in firestore is empty.
Is there any way to add onComplete to the getDownloadURL() function?
or any other options to run the firestore upload after the images done with uploading?

Related

Firebase returns null photoUrl

I am building a mock social media app that allows users upload profile pictures to create their profiles. I am building this app in flutter.
Right now, here's my uploadPic method:
Future uploadPic(BuildContext context) async{
String fileName = basename(_image.path);
FirebaseStorage storage = FirebaseStorage.instance;
var photoUrl;
Reference ref = storage.ref().child(fileName);
var storedImage = File(_image.path);
UploadTask uploadTask = ref.putFile(storedImage);
uploadTask.then((res) {
photoUrl = res.ref.getDownloadURL();
});
print("photo url -- $photoUrl");
await widget.user?.updatePhotoURL(photoUrl);
await FirebaseAuth.instance.currentUser?.updatePhotoURL(photoUrl);
}
I have added the right permissions in my firebase console to allow read and write to the database. I know this because when I check firebase storage, I see the pictures have been uploaded successfully. However, when I try to print the returned photo url (after the upload task completes), I get a null value. This is a problem when I try to access the photo in other areas in the app, because the user photoUrl in firebase is null.
Is there anything I am doing wrong concerning the upload of the pic to firebase?
Also, my terminal returns this: No App Check token for request.. I'm wondering if this has anything to do with the issue?
Any help would be greatly appreciated!
your problem is simple, it's exactly from here:
var photoUrl;
uploadTask.then((res) {
photoUrl = res.ref.getDownloadURL();
});
print(photoUrl); // null
the problem is you are trying to print photoUrl variable without waiting for the future uploadTask to finish its work which results null.
the solution is to wait for uploadTask future before printing the photoUrl variable:
var photoUrl;
await uploadTask.then((res) async {
photoUrl = await res.ref.getDownloadURL();
});
print(photoUrl);
the solution on your code:
Future uploadPic(BuildContext context) async{
String fileName = basename(_image.path);
FirebaseStorage storage = FirebaseStorage.instance;
var photoUrl;
Reference ref = storage.ref().child(fileName);
var storedImage = File(_image.path);
UploadTask uploadTask = ref.putFile(storedImage);
await uploadTask.then((res) async {
photoUrl = await res.ref.getDownloadURL();
});
print("photo url -- $photoUrl");
await widget.user?.updatePhotoURL(photoUrl);
await FirebaseAuth.instance.currentUser?.updatePhotoURL(photoUrl);
}

Define Firebase cloud storage path in flutter

I am having trouble defining path for Firebase cloud storage.
I would like it to be -
user id -> firestore doc id -> folder's name.
currently, I successfully save the images in this way.
class FirebaseStorageService {
final String imageName;
FirebaseStorageService({required this.imageName});
get imageFileName =>
imageName + DateTime.now().millisecondsSinceEpoch.toString();
//get firestore doc id
final postid = FirebaseFirestore.instance.collection('properties').doc().id;
//get user id
final String? userid = FirebaseAuth.instance.currentUser!.uid;
//! Upload gallery
Future<String> saveGalleryInCloudStorage({
required File file,
}) async =>
await upload(
file: file,
path: '$userid/$postid/Property Gallery/$imageFileName',
contentType: 'image/png');
/// Generic file upload for any [path] and [contentType]
Future<String> upload({
required File file,
required String path,
required String contentType,
}) async {
final storageReference = FirebaseStorage.instance.ref().child(path);
final uploadTask = storageReference.putFile(
file, SettableMetadata(contentType: contentType));
final snapshot = await uploadTask;
final downloadUrl = await snapshot.ref.getDownloadURL();
return downloadUrl;
}
}
However, the problem I am having is the postid (that is used in firebase cloud storage path) is not same with firestore doc id.
How do I make them to be the same?
Thanks in advance!!
.collection('properties').doc()
the doc is empty hence firebase generates an auto id.
What you can do is Create an empty doc get a doc id, use the id to save the file, and when saving your firestore doc just update the empty doc
create empty doc
final documentReference = await FirebaseFirestore.instance.collection('mycoll').add({'id':''});
use doc id to save file obtained from
documentReference.id
makes this redudant
//get firestore doc id
final postid = FirebaseFirestore.instance.collection('properties').doc().id;
on done saving file , save your doc with the id above
FirebaseFirestore.instance.collection('properties').doc(documentReference.id)
.set(servicemodel.toJson());```
You can upload Image and update fields related withthis function. Its work for me.
static String staticImagePath= "";
final FirebaseAuth _auth = FirebaseAuth.instance;
File? file;
Future uploadImageToFirebaseStorage() async {
var _user = _auth.currentUser!.uid;
var _propertiesCollection= FirebaseFirestore.instance
.collection('Properties')
.where('postId', isEqualTo: _user);
var querySnapshots = await _propertiesCollection.get();
try {
var _image = await ImagePicker().pickImage(source: ImageSource.gallery);
file = File(_image!.path);
firebase_storage.Reference _refPath = firebase_storage
.FirebaseStorage.instance
.ref()
.child('MyImageRepo')
.child(_auth.currentUser!.uid);
firebase_storage.UploadTask _uploadTask = _refPath.putFile(file!);
String _url = await (await _uploadTask).ref.getDownloadURL();
staticImagePath = _url.toString();
await _propertiesCollection.doc(_auth.currentUser!.uid).update(({
'postId': staticImagePath,
}));
} catch (e) {
return Center(child: Text(e.toString()));
}
}

Add document to collection in Cloud Firestore without overwrite previous document Flutter

In my flutter application I need to add document into a collection "influencerPost" and every time user adds a new "post" this document must be added to the previous... but in this moment I just get an overwrite of the previous document.
as you can see by my method, I have uploadImage future
which picked up image and store it to Storage in Firebase.
after that I create a collection called influencerPost and I must add every time new post is generate new documents without overwrite
this is the full code:
Future uploadImage(BuildContext context) async {
String fileName = basename(_postImage.path);
Reference firebaseStorageRef =
FirebaseStorage.instance.ref().child('postImage/$fileName');
UploadTask uploadTask = firebaseStorageRef.putFile(_postImage);
TaskSnapshot taskSnapshot = await uploadTask.whenComplete(() => null);
final String downloadUrl = await taskSnapshot.ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('influencerPost')
.doc(firebaseUser.uid)
.set({
"imageUrl": downloadUrl,
'postText': IfUserProfile.post
});
setState(() => CircularProgressIndicator());
}
In this way I get all but the documents are overwrite instead i need to keep the previous and add a new one.
Since you want to maintain multiple post against user you have to create sub collection. Check below code where I have added sub collection .collection("post")
Future uploadImage(BuildContext context) async {
String fileName = basename(_postImage.path);
Reference firebaseStorageRef =
FirebaseStorage.instance.ref().child('postImage/$fileName');
UploadTask uploadTask = firebaseStorageRef.putFile(_postImage);
TaskSnapshot taskSnapshot = await uploadTask.whenComplete(() => null);
final String downloadUrl = await taskSnapshot.ref.getDownloadURL();
await FirebaseFirestore.instance
.collection('influencerPost')
.doc(firebaseUser.uid)
.collection("post")
.add({
"imageUrl": downloadUrl,
'postText': IfUserProfile.post
});
setState(() => CircularProgressIndicator());
}

How to download images from firebase storage to current user Cloud Firestore Flutter?

This is the code used to save a chosen image from image picker to firebase storage.
Future uploadPic(BuildContext context) async {
String fileName = basename(_image.path);
StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_image);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
setState(() {
print("Profile Picture uploaded");
Scaffold.of(context)
.showSnackBar(SnackBar(content: Text('Profile Picture Uploaded')));
});
}
Upon choosing an image as an authenticated user (I took care of authentication already) how can I convert the image as a URL for the current user's cloud firestore from which that image can appear in different areas of the app?
I save user information via the current user's uid as such for further context:
Future<void> userSetup(String displayName) async {
int plastics = 0;
final CollectionReference users =
FirebaseFirestore.instance.collection('Users');
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
users.doc(uid).set({'displayName': displayName, 'uid': uid});
users.doc(uid).update({'plastics': plastics});
return;
}
Posting as Community Wiki, based in the comments.
You can use the below code - adapted for your needs, based in this answer here - to save an image into Firestore.
Future Build() async {
String fileName = basename(_image.path);
StorageReference reference = storage.ref().child('image');
StorageUploadTask uploadTask = reference.putFile(fileName);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
String url = await taskSnapshot.ref.getDownloadURL();
imageUrl1 = url;
return url;
}
With the function written this way, you should be able to save the image from a specific path into your database. In addition to that, bear in mind that this code should be a starting point for you, as changes might be needed, considering variable names and locations.

Why I am not able to update the imageurl using these functions in firestore flutter?

I have initialized url to null at first then i am adding data in my firestore first document and then image
String url='';
StorageTaskSnapshot storageTaskSnapshot;
Future<Project> updateUserData(Project project) async {
docref=await firestoreInstance.collection('projects').add(
{
'id': project.id,
'title': project.title,
'description': project.description,
'duration': project.duration,
'members': project.members,
'complexity': project.complexity,
'affordability': project.affordability,
'prequisites': project.prequisites,
'contact': project.contact,
'imageurl': 'https://bitsofco.de/content/images/2018/12/broken-1.png',
},
);
fileName = basename(project.image.path);
firebaseStorageRef =
FirebaseStorage.instance.ref().child(fileName);
uploadTask = firebaseStorageRef.putFile(project.image);
String photourl = await (await uploadTask.onComplete).ref.getDownloadURL();
url= photourl.toString(); //updating the null initialized url here
notifyListeners();
}
Then i am using this function to update the imageurl in the previously saved doc.
Future<Void> updatedata() async{
await Firestore.instance
.collection('projects')
.document(docref.documentID)
.updateData({
'imageurl': url,
});
notifyListeners();
}
Everytime im calling these two functions in another widget using provide,r doc and image are getting uploaded but url is returning null and im not able to fetch the image.
Provider.of<DatabaseService>(context,listen: false).updateUserData(finalproj);
Provider.of<DatabaseService>(context,listen: false).updatedata();
You'll need to wait for updateUserData to be finished before calling updatedata, otherwise you can't be certain that docref is set correctly.
await Provider.of<DatabaseService>(context,listen: false).updateUserData(finalproj);
Provider.of<DatabaseService>(context,listen: false).updatedata();

Resources