Flutter GestureDetector with multiple futures - flutter

I got 2 futures. When I press a GestureDetector I want the first to be completed and then run the second one. But it doesn’t work. What can I do to fix the issue?
Here is my code.
GestureDetector(
onTap: () => pickImage(), uploadImageToFirebase(),
),
Future pickImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(pickedFile.path);
});
}
Future uploadImageToFirebase(BuildContext context) async {
String fileName = basename(_imageFile.path);
StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('uploads/$fileName');
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_imageFile);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
taskSnapshot.ref.getDownloadURL().then(
(value) => imageUrl = value,
);
}

You can use Future.wait() , It takes a List of Futures and return when all underlying future completes/resolves.
In your code, You can do something like this,
GestureDetector(
onTap: () => pickImageandUploadToFirebase(),
),
The method pickImageandUploadToFirebase() looks like this,
Future<void> pickImageandUploadToFirebase() async {
await Future.wait([
pickImage(),
uploadImageToFirebase(),
]);
}
and you already have the 2 methods pickImage() and uploadImageToFirebase()
Hope this helps, Happy fluttering !

upload this after image pick done,
like this
GestureDetector(
onTap: () => pickImage(context);
),
Future pickImage(context) async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(pickedFile.path);
});
uploadImageToFirebase(context);
}
Future uploadImageToFirebase(BuildContext context) async {
String fileName = basename(_imageFile.path);
StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('uploads/$fileName');
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_imageFile);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
taskSnapshot.ref.getDownloadURL().then(
(value) => imageUrl = value,
);
}
also, another option is if you need to call one by one in single method.
then return data from first method "pickImage" after retrun done, you call second "uploadImageToFirebase",

Related

ImageCropper use with Uint8List file -flutter

I'm using image_picker & ImageCropper packages. I want to save a user-given picture in firestore database. So, I use functions like this.
First, set File? _image;
Functions for cropping & picking
Future _pickImage(ImageSource source) async {
Navigator.of(context).pop();
try {
final image = await ImagePicker().pickImage(source: source);
if (image == null) return;
File? img = File(image.path);
img = await _cropImage(imageFile: img);
setState(() {
_image = img;
});
} on PlatformException catch (e) {
print(e);
Navigator.of(context).pop();
}
}
Future<File?> _cropImage({required File imageFile}) async {
CroppedFile? croppedImage =
await ImageCropper().cropImage(sourcePath: imageFile.path);
if (CroppedFile == null) return null;
return File(croppedImage!.path);
}
and use this to save data in firestore
Future<String> uploadImageToStorage(
File file,
) async {
file
Reference ref =
_storage.ref().child("profilePics").child(_auth.currentUser!.uid);
UploadTask uploadTask = ref.putData(file);
TaskSnapshot snap = await uploadTask;
String downloadUrl = await snap.ref.getDownloadURL();
return downloadUrl;
}
Above function not work for File type data, It support for Uint8List. So, What can I do for this?
Next problem is, I'm getting File type data with ImagePicker for profile picture. Is it not problem?
Try changing your _cropImage-Method to return XFile? like this:
Future<XFile?> _cropImage({required File imageFile}) async {
CroppedFile? croppedImage =
await ImageCropper().cropImage(sourcePath: imageFile.path);
if (CroppedFile == null) return null;
return XFile(croppedImage!.path);
}
You also have to change the paramter of uploadImageToStorage to XFile file. Then you can use file!.readAsBytes(); to get a Uint8List.
Future<String> uploadImageToStorage(
XFile file,
) async {
Reference ref =
_storage.ref().child("profilePics").child(_auth.currentUser!.uid);
final fileBytes = await file.readAsBytes();
UploadTask uploadTask = ref.putData(fileBytes);
TaskSnapshot snap = await uploadTask;
String downloadUrl = await snap.ref.getDownloadURL();
return downloadUrl;
}

Flutter rebuilds widget without waiting for code execution

I have a function to upload image to the server. However the widgets starts rebuilding while the image is being uploaded and does not execute code after image is uploaded.
InkWell(
child: Icon(
Icons.camera,
size: 50,
color: Colors.red[400],
),
onTap: () {
_imageFile =
_picker.getImage(source: ImageSource.camera);
_imageFile.then((file) async {
if (file != null) {
fileName = file.path.toString();
var res = await Auth.uploadImage(file);
print("Response for image upload is : ");
print(res);
await setUserData();
}
});
},
)
This is the output on the console from print statements
I/flutter (10171): Calling build Method
I/Timeline(10171): Timeline: Activity_launch_request time:68831133
I/flutter (10171): Uploading image to server
I/flutter (10171): Calling build Method
I/flutter (10171): Image uploaded successfully
As can be seen above no other code is executed and the widget has rebuilt itself. What am I possibly doing wrong?
_imageFile = _picker.getImage(source: ImageSource.camera);
its not right, getImage is an Asynchronous function so you need to wait for it to finish.
do this - _imageFile = await _picker.getImage(source: ImageSource.camera);
If you want to use then do it like this,
_picker.getImage(source: ImageSource.camera).then((image)...your code...)
That's because when you're using _imageFile = _picker.getImage(source: ImageSource.camera); the _imageFile result will come in the future and your next code is executed.
You can fixed the problem either using await:
onTap: () async {
_imageFile =
await _picker.getImage(source: ImageSource.camera);
if (_imageFile != null) {
fileName = file.path.toString();
var res = await Auth.uploadImage(file);
print("Response for image upload is : ");
print(res);
await setUserData();
}
},
Or keep using then with a slight change:
onTap: () {
_picker.getImage(source: ImageSource.camera)
.then((file) async {
if (file != null) {
fileName = file.path.toString();
var res = await Auth.uploadImage(file);
print("Response for image upload is : ");
print(res);
await setUserData();
}
});
},
See explanation about await & then: Async/Await/then in Dart/Flutter

How to upload image on cloud firestore linked to an entry?

I am trying to upload image on cloud firestore. But there is a error I am not able to catch.
I am using the code under uploadFile from here
Future<void> getImage() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
widget._image = image;
print("added image");
});
uploadImage();
}
Future uploadImage() async {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(widget._image);
StorageTaskSnapshot storageTaskSnapshot = await uploadTask.onComplete;
storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
widget.photourl = downloadUrl;
}, onError: (err) {
print('Error');
});
}
'added image' prints on the terminal, so there isn't a problem in that it seems.
photourl is null, but it should contain the url.
Thank you.
In the above code, you are just getting an image URL from Firebase storage. You need to update the photoURL in Firestore also.
Future<void> updateOneField = database
.collection('entries')
.document('D3idV9o7uWT4pWvby643')
.updateData(
{
"photourl": downloadUrl
});
It seems the problem was because of state of widget. This solved it
Future uploadImage() async {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(widget._image);
StorageTaskSnapshot storageTaskSnapshot = await uploadTask.onComplete;
storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
setState(() {
widget.photourl = downloadUrl;
});
}, onError: (err) {
print('Error');
});
}

Save Image Url in Cloud FireStore

I try to create details of product in Cloud FireStore. Create document and save image in storage is all works. Mu issue is image url doesn't save in document.
dart file
class ProductService {
Firestore _firestore = Firestore.instance;
void createProduct(_nameproductController, _priceproductController,
_currentCategory, url) async {
_firestore.collection("products").document().setData({
'name': _nameproductController,
'price': _priceproductController,
'category': _currentCategory,
'image': url,
});
}
}
upload image
void uploadImg() async {
var timekey = DateTime.now();
fb.StorageReference storageReference =
fb.storage().ref('imgProduct/${timekey.toString()}.jpg');
fb.UploadTaskSnapshot uploadTask = await storageReference
.put(_image1, fb.UploadMetadata(contentType: 'image/jpg'))
.future;
var imageUrl = await uploadTask.ref.getDownloadURL();
url = imageUrl.toString();
print('Image Url' + url);}
submit button
RaisedButton(
onPressed: () async {
if (_formKeyProduct.currentState.validate()) {
uploadImg();
ProductService().addProduct(
_nameproductController.text,
_priceproductController.text,
_currentCategory.categoryname.toString(),
url,
);
_formKeyProduct.currentState.reset();
_nameproductController.clear();
_priceproductController.clear();
}
setState(() {
_currentCategory = null;
});
},
you need to await uploadImg();

Upload Image Flutter Storage

i am use 'image_picker_web/image_picker_web.dart' in my app. Now when I choosed image, this image displayed, it's work. But when i try to save image in storage nothing happens.
Uint8List _image1;
Future getImg() async {
Uint8List tempImg = await ImagePickerWeb.getImage(asUint8List: true);
if (tempImg != null) {
setState(() {
// debugPrint(tempImg.toString());
_image1 = tempImg;
});
}}
save in storage:
void uploadImg() async {
final StorageReference productImg =
FirebaseStorage.instance.ref().child('ProductImg');
var timekey = DateTime.now();
final StorageUploadTask uploadTask =
productImg.child(timekey.toString() + 'jpg').putData(_image1);
var imageUrl = await (await uploadTask.onComplete).ref.getDownloadURL();
url = imageUrl.toString();
print('Image Url' + url);}
button:
RaisedButton(
onPressed: () {
uploadImg();
}
what am I doing wrong?
Give this a try:
final file = File.fromRawPath(uint8list);
final ref = FirebaseStorage.instance.ref().child("users/some_id/ProductImg.jpg");
final task = ref.putFile(file, StorageMetadata(contentType: "image/png"));
final snapshot = await task.onComplete;
if (snapshot.error != null) throw snapshot.error;
final downloadURL = await snapshot.ref.getDownloadURL();