getting image from firebase storage not working - flutter

i am new to flutter and i am trying to make an app which take data from user and make a widget out of it (Classified ads), so far everything is working. but the images from firebase storage is not loading, i have the image url in database ,
for the name its working
Text(snapshot.data.documents[index]['item Name'],),
but for images it gives error
index == null
? Image.asset('assets/afghan.png')
: Image.network(snapshot.data.documents[index]['image 1 Url'],),
the ERROR
Invalid argument(s): No host specified in URI file:///data/user/0/com.example.thisOne/cache/image_picker1382407617041908118.jpg

Change this:
Image.network(snapshot.data.documents[index]['image 1 Url'],)
into this:
Image.file(snapshot.data.documents[index]['image 1 Url'],)
The image url is not valid, this is how you have to save the image in the database:
StorageTaskSnapshot snapshot = await storage
.ref()
.child("images/$imageName")
.putFile(file)
.onComplete;
if (snapshot.error == null) {
final String downloadUrl =
await snapshot.ref.getDownloadURL();
await Firestore.instance
.collection("images")
.add({"url": downloadUrl, "name": imageName});
setState(() {
isLoading = false;
});
You are not saving it correctly to the database, you need to get the downloadUrl from firebase storage which will contain a valid url (https://...) and add it to Firestore. Then you can use Image.network

Related

Uploading image into Floating Action Button, set state not working

I have a floating action button that I want a user to click to take a picture with their camera and then have that image replace the camera icon on the floating action bar button.
Here is the code for my FAB, and including uploading the image to firestore storage.
floatingActionButton: FloatingActionButton.large(
heroTag: "add image",
backgroundColor: const Color(0xFF93C3B9),
child: (imageURL == ' ')
? const Icon(Icons.add_a_photo_outlined)
: Image.network(imageURL),
//open add gear page
onPressed: () async {
// todo: upload an image to Firebase Storage
//Take picture
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(source: ImageSource.camera);
if (file == null) return;
String uniqueFileName =
DateTime.now().millisecondsSinceEpoch.toString();
//Get reference to storage root
Reference referenceRoot = FirebaseStorage.instance.ref();
Reference referenceDirImages = referenceRoot.child('images/$userID');
Reference referenceImageToUpload =
referenceDirImages.child(uniqueFileName);
try {
//upload image
await referenceImageToUpload.putFile(File(file.path));
//get download URL
setState(() async {
imageURL = await referenceImageToUpload.getDownloadURL();
print(imageURL);
});
//upload path to fireStore database
} catch (error) {}
},
),
After the image uploads it's like the set state is not working to replace the icon with the image. The odd part is is I crtl-s and save in Visual Studio Code then the widgets seem to rebuild and then the image is visible there...
So after playing around with my code a bit I decided to edit the above code and take tha await function out of the setState() and make setState() not async anymore:
//get download URL
String tempUrl = await referenceImageToUpload.getDownloadURL();
setState(() {
print("--------- Set State -----------");
imageURL = tempUrl;
print("--------- Set State end -----------");
});
print("New image url $imageURL ------------");
not sure why it works, but this solves my issue.
By your description of the issue, I think you might be using StatelessWidget instead of StatefulWidget.
You see the button change when performing a hotreload because the value of imageURL is correctly changing internally, but you need a StatefulWidget to update the UI also.
Hope it helps!

Unhandled Exception: [cloud_firestore/not-found] Some requested document was not found. Alert related to delete()

In my code, I pass the url of an image (stored in firebase storage) in a document from screen 1 to screen 2. In screen 2, I have a button to delete the document; but, first, I check if the url value is not empty, so I can delete the image first in storage and then delete the hole document
if(widget.image != ''){
await ImageService().deleteFile(image: widget.image, collectionPath: collectionPath, docId: widget.questionRef);
}
await doc.delete().then((value) {
Navigator.pop(context);
});
ImageService().deleteFile :
dynamic deleteFile(
{required String image,
required String collectionPath,
required String docId}) {
FirebaseStorage.instance
.refFromURL(image)
.delete()
.then((value) {})
.then((value) {
FirebaseFirestore.instance
.collection(collectionPath)
.doc(docId)
.update({'image': ''});
});
}
It works fine, but I get the alert
Unhandled Exception: [cloud_firestore/not-found] Some requested document was not found.
The hole process works fine, this message appears when deleting the document, but it seems that its related to update(), right? How is it possible? What is happening?

How to get value of variable from function?

I am trying to get value from a function and store it in a variable but I am getting null.
String imgUrl='';
getUrlSP() async {
SharedPreference preferences
=await SharedPreferences.getInstance();
String Url =
preferences.getString('imageUrl').toString();
setState(() {
imgUrl=Url;
});
print('Printing Image Url inside function:${imgUrl}');
}
outside function
print('Image Url :${imgUrl}');
The results I got in the terminal are
I/flutter (32164): Image Url :
I/flutter (32164): Image Url Stored in Prefs
is:https://firebasestorage.googleapis.com/v0/b/veeluser.appspot.com/o/User%20Images%2FdCP6WEESxfYNDIMqtt57n2BsxYf1?alt=media&token=d864a502-209f-4262-9860-b9d4d3222091
_As from the above results that I got in terminal I am not getting the value of imageUrl outside the function._As I am new to flutter so if there is an error or there is any other solution please share it.
That is expected. since your getUrlSP function is declared as async, you'll need to use await when calling it to ensure it completes (and sets imgUrl) before the rest of your code runs.
So:
await getUrlSP();
print('Image Url :${imgUrl}');
I recommend taking the Flutter codelab Asynchronous programming: futures, async, await
should be used setString() to add a string value to the shared preferences .
Example :
String imgUrl='';
getUrlSP() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('imageUrl', imgUrl);
print('==> ${imgUrl} <==');
}

Flutter/Firebase read specific user's file from app

I have question regarding Firebase, I'm making a Flutter App that uses Firebase for user authentication with email & password which is already done, now each user would have specific document (.pdf) uploaded in Storage via console and only that user would have access to his own document that would be shown in the app once he's logged in.
My question is, based on quick research I've noticed that I cannot set a unique ID to a file in storage (if i upload an image for example), so how can I determine that only a specific user can have access to a specific file. I've also taken a look into Firebase Security Rules but I'm not sure if that's enough to determine or do I need custom written code in Flutter as well?
Thanks.
Expanding on #brookyounas's answer:
Get the pdf location from firebase storage then you should have a 'users' collection with documentId of the current user and save the pdf location (link) in that document.
For getting this storage file link, use:
String fileUrl = "";
Future uploadFile() async {
showLoading();
String fileName = ""; //give your file name or just use the firebaseUserId
var ref = FirebaseStorage.instance
.ref()
.child('UserPDFs')
.child('$fileName.pdf');
await ref.putFile(file!).then((val) async {
fileUrl = await val.ref.getDownloadURL();
setState(() {});
log("file url: $fileUrl");
await FirebaseFirestore.instance.collection("users").update({"pdfFileUrl":fileUrl});
dismissLoadingWidget();
});
}
so every time user is logged-in, get the current user-id and then use it.
var firebaseUserId = await FirebaseAuth.instance.currentUser().uid;
String pdfFileUrl = "";
#override
void initState() {
super.initState();
setState(() {
getPdf();
});
}
void getPdf(){
Firestore.instance
.collection("users")
.doc(firebaseUserId) //changed to .doc because .document is deprecated
.get().then({
pdfFileUrl = value[fileUrl];
});
after this use this link with : syncfusion_flutter_pdfviewer - a package for viewing pdfs online
more on this here: A StackOverflow post about this
get .pdf location from firebase storage(access token) then you should have 'users' collection with documentId of current user and save .pdf location in the document.
so every time user is logged-in, get the current user-id and then use it.
var firebaseUserId = await FirebaseAuth.instance.currentUser().uid;
#override
void initState() {
super.initState();
setState(() {
getPdf();
});
}
void getPdf(){
Firestore.instance
.collection("users")
.doc(firebaseUserId) //changed to .doc because .document is deprecated
.get();

Upload race condition - Google Firebase Storage

I am attempted to update an avatar on my app and then load and display it once done. However, I am seeing the following errors which seem to indicate a false positive or race condition when the image has actually finished uploading.
I'm using a CicleAvatar widget, but also attempted with NetworkImage and am experiencing the same issues. I have also attempted .then/onComplete and various others outside of a delayed or wrapping it in a completer.
What is the best way to handle Firebase storage upload and immediate download without error§
Example Error n attempting to retrieve the image from the DownloadURLL:
════════ Exception caught by image resource service
════════════════════════════ HTTP request failed, statusCode: 503,
!isImageProcessing
? GestureDetector(
onTap: () => _uploadAvatarImage(),
child: CircleAvatar(
minRadius: 40,
backgroundColor: Colors.grey,
backgroundImage: NetworkImage(user.imageURL),
),
)
: Center(
child: CircularProgressIndicator(),
),
The actual upload of the file is being managed in this function/class
class StorageController {
static Future<String> storeAvatarImage(File file) async {
// Get user UUID to reference avatar;
String uuid = await identityBloc.retrieveActiveUUID();
String downloadURL;
TaskSnapshot ts;
ts = await firebase_storage.FirebaseStorage.instance
.ref('avatars/$uuid-avatar.png')
.putFile(file);
downloadURL = await ts.ref.getDownloadURL();
User user = await ProfileDataController.retrieveUserProfile();
user.imageURL = downloadURL;
await ProfileDataController.createUserProfile(user);
downloadURL = downloadURL;
return downloadURL;
}
}
I think you are not properly awaiting for the file upload. Can you change this line to read:
ts = await firebase_storage.FirebaseStorage.instance
.ref('avatars/$uuid-avatar.png')
.putFile(file);
// removed the below part
// .snapshot;
The image would update if there are listeners to listen to changes in the changed user avatar.
What I would advise as a workaround is store the avatarUrl to firestore or rtdb, there you can set a listener that updates the UI on the frontend when a change is written there.
Initially, the avatarUrl field would be null then when a user uploads a new picture the field is then a string and you can supply it to your UI