Why I use setState in async funtion not update state (Flutter)? - flutter

Why my _image not update?
I need _image properties update when user pick new image from gallery or camera, but when user pick new images I use setState for set new value to _image but it didn't work(didn't update UI).
Here my code I have problem:
Sorry I cant full source because editor of stackoverflow complain to many code.
Statefull Class:
enum ChooseMedia { camera, gallery }
File _image;
void getImage(ChooseMedia media) async {
if (media == ChooseMedia.camera) {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
var pathLocal = await getApplicationDocumentsDirectory();
await image.copy('${pathLocal.path}/profileImage.jpg').then((_) {
setState(() {
_image = image;
});
});
}
if (ChooseMedia.gallery == media) {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
var pathLocal = await getApplicationDocumentsDirectory();
await image.copy('${pathLocal.path}/profileImage.jpg').then((_) {
setState(() {
_image = image;
});
});
}
}
#override
Widget build(BuildContext context) {
return PopupMenuButton(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
onSelected: (ChooseMedia media) {
getImage(media);
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<ChooseMedia>>[
const PopupMenuItem<ChooseMedia>(
value: ChooseMedia.gallery,
child: ListTile(
leading: Icon(
Icons.picture_in_picture,
),
title: Text('From galaxy'),
),
),
const PopupMenuItem<ChooseMedia>(
value: ChooseMedia.camera,
child: ListTile(
leading: Icon(Icons.camera),
title: Text('Take picture'),
),
),
],
child: Container(
decoration: BoxDecoration(),
padding: EdgeInsets.all(7),
child: CircleAvatar(
backgroundImage: _image == null
? AssetImage('assets/images/profile.jpg')
: FileImage(_image))),
);
}

You are mixing 'await' and 'then'
Just do
var copiedImage = await image.copy('${pathLocal.path}/profileImage.jpg');
setState(() {
_image = copiedImage;
});

Related

Flutter - how to compress an image

I am trying to compress image that is picked via file_picker package. I am compressing image with flutter_native_image. But image is not being compressed.
Where have I gone wrong?
P.S - I can't use image_picker package because it stopped working and I had to switch to file_picker.
class UploadSingleImageToFirestore extends StatefulWidget {
const UploadSingleImageToFirestore({super.key});
#override
State<UploadSingleImageToFirestore> createState() =>
_UploadSingleImageToFirestoreState();
}
class _UploadSingleImageToFirestoreState
extends State<UploadSingleImageToFirestore> {
File? _pickedImage;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarTitle(context, 'Upload Single Image'),
backgroundColor: ZayyanColorTheme.zayyanGrey,
body: _pickedImage != null
? Center(
child: Column(
children: [
ANPFormContainer(
fieldTitle: 'Single Image',
subTitle: 'Pick Single Image',
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 140),
child: Image.file(
File(_pickedImage!.path),
height: 300,
width: 300,
),
),
),
addVerticalSpacer(25),
ElevatedButton(
onPressed: () => pickImage(),
child: const Text('Pick Image')),
ElevatedButton(
onPressed: () => _updateMedia(),
child: const Text('Upload Images')),
],
),
)
: InkWell(
onTap: () => pickImage(),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(Icons.add_a_photo),
SizedBox(height: 10),
Text('Tap anywhere to pick images')
],
),
),
),
);
}
pickImage() async {
FilePickerResult? result =
await FilePicker.platform.pickFiles(type: FileType.image);
if (result != null) {
File file = File(result.files.single.path!);
print(file);
compressImage(file);
setState(() {
_pickedImage = file;
});
} else {
print("No file selected");
}
}
compressImage(path) async {
if (_pickedImage == null) return;
File compressedFile = await FlutterNativeImage.compressImage(
path,
quality: 10,
percentage: 20,
targetWidth: 600,
);
return compressedFile;
}
_updateMedia() async {
CollectionReference collectionRef =
FirebaseFirestore.instance.collection('Users');
final coverUrl = await context
.read<FirebaseStorageService>()
.saveCoverInCloudStorage(
file: _pickedImage!,
state: 'Test State',
township: 'Test Township',
propertyType: 'Test House',
propertyid: 'HYG-1234');
return collectionRef
.doc('gMH1s0XUIvWdD2fYfqMvPc915a03')
.update({
'logo': coverUrl,
})
.then((value) => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Property Info Updated'))))
.catchError((error) => ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('+++ Failed to update user: $error"'))));
}
}
If your requirement is just images, Use image_picker instead of file_picker.
Fetching from image picker
You can use the built in imaqeQuality property from ImagePicker to compress the image. This property takes a value between 0 and 100 and represents a percentage of the original image quality.
File _image;
Future getImage() async {
var image = await ImagePicker.pickImage(
source: ImageSource.gallery,
imageQuality: 25,
);
setState(() {
_image = image;
});
}
Use flutter_native_image to compress
Future<File> compressFile(File file) async{
File compressedFile = await FlutterNativeImage.compressImage(file.path,
quality: 5,);
return compressedFile;
}
Also Refer: Flutter the best way to compress image

Can't compress ImagePicker photo Flutter, returns null value

I tried compressing a photo taken using the ImagePicker Package, with the flutter_image_compress package. However, the photo '_file' returns a null value, instead of the newly compressed image. This code works when i dont try to compress it.
Future<Uint8List> testComporessList(Uint8List list) async {
var result = await FlutterImageCompress.compressWithList(
list,
minHeight: 1920,
minWidth: 1080,
quality: 96,
);
return result;
}
_selectImage(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text('Create a Post'),
children: [
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Take a photo'),
onPressed: () async {
Navigator.of(context).pop();
Uint8List file = await pickImage(
ImageSource.camera,
);
Uint8List file2 = await testComporessList(file);
setState(() async {
_file = await testComporessList(file2);
}
);
},
),
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
void clearImage() {
setState(() {**strong text**
_file = null;
});
}

How do i disable the Elevated button when the Image.Network (from firebase) is null

I have an Elevated Button, which will save data into the firebase. I want to disable this button when the Image.Network is null.
But somehow when i delete the button, the Elevated button is not getting disabled. Just for your info, the image is coming from Firebase Storage Can someone help.
// Here are the codes.....
// Select and image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
Future<void> _upload(String inputSource) async {
final picker = ImagePicker();
try {
pickedImage = (await picker.pickImage(
source: inputSource == 'camera'
? ImageSource.camera
: ImageSource.gallery,
maxWidth: 1920));
final String fileName = path.basename(pickedImage!.path);
File imageFile = File(pickedImage!.path);
try {
// Uploading the selected image
await FirebaseStorage.instance
.ref(widget.value2)
.child(widget.value4)
.child(widget.value5)
.child(fileName)
.putFile(
imageFile,
SettableMetadata(customMetadata: {
'Station': widget.value2,
'Facility': widget.value4,
'Item': widget.value5,
}));
// Refresh the UI
setState(() {});
} on FirebaseException catch (error) {
if (kDebugMode) {
debugPrint(error.toString());
}
}
} catch (err) {
if (kDebugMode) {
debugPrint(err.toString());
}
}
}
// Retrieve the uploaded images
// This function is called when the app launches for the first time or when an image is uploaded or deleted
Future<List<Map<String, dynamic>>> _loadImages() async {
List<Map<String, dynamic>> files = [];
final ListResult result = await FirebaseStorage.instance
.ref(widget.value2)
.child(widget.value4)
.child(widget.value5)
.list();
final List<Reference> allFiles = result.items;
await Future.forEach<Reference>(allFiles, (file) async {
final String fileUrl = await file.getDownloadURL();
final FullMetadata fileMeta = await file.getMetadata();
files.add({
'url': fileUrl,
'path': file.fullPath,
'Facility': fileMeta.customMetadata?['Facility'] ?? 'Nobody',
});
});
return files;
}
Future<void> _delete(String ref) async {
await FirebaseStorage.instance.ref(ref).delete();
setState(() {});
}
//To display the image
Row(
children: [
Flexible(
child: FutureBuilder(
future: _loadImages(),
builder: (context,
AsyncSnapshot<
List<
Map<String, dynamic>>>
snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return ListView.builder(
itemExtent: 320,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount:
snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
//final Map<String, dynamic>
image = snapshot.data![index];
return Column(
children: [
Image.network(
image?['url'],
width: 300,
height: 250,
fit: BoxFit.cover,
),
const SizedBox(height: 5),
//Text (
//image?['Facility']
//),
IconButton(
onPressed: () =>
_delete(
image?['path']),
icon: const Icon(
Icons.delete,
color: Colors.red,
),
),
],
);
},
);
}
return const Center(
child:
CircularProgressIndicator(),
);
},
),
),
],
)
//Here is the code for the Elevated Button: -
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton.icon(
label: const Text('Save'),
icon: const Icon(Icons.save_alt_rounded),
onPressed: (functionality <= 99.0 &&
image != null)
|| (functionality == 100.0 && comments == '')
? () async {
final uploadData = {
'Project': widget.value1,
'Station': widget.value2,
'Name': widget.value3,
'Facility': widget.value4,
'Item': widget.value5,
'DateTime': dateTimeEsc,
'Total In Service':
totalInService,
'Functionality (%)':
functionality,
};
await FirebaseFirestore.instance
.collection('KGL')
.doc(widget.value2 +
'_' +
widget.value4 +
'_' +
widget.value5)
.update(uploadData);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext
context) =>
super.widget));
}
: null,
)),
I think this is what you try to accomplish?
Feel free to comment if it doesn't work.
IconButton(
onPressed: () {
if(image?['url'] != ''){
_delete(image?['path']),
}
},
icon: const Icon(
Icons.delete,
color: Colors.red,
),
),

Could not be able to keep image permanently in flutter app

I have been tried to load a image from gallery an keep it permanently in app. But when I move to a different route and return to the image route previously loaded image has been disappeared.
'''
return Scaffold(
appBar: AppBar(
title: const Text('test'),
),
body: ListView(
children: [
ElevatedButton(
child: const Text('Upload a picture'),
onPressed: () async {
try {
final image =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return;
final directory = await getApplicationDocumentsDirectory();
log('imagevalue $image');
final name = basename(image.path);
final imagefile = File('${directory.path}/$name');
final imagePermanent =
await File(image.path).copy(imagefile.path);
setState(() {
_image = imagePermanent;
log('_imageV $_image');
});
} on PlatformException catch (e) {
log(e.toString());
}
},
),
_image != null
? Image.file(
_image!,
height: 160,
width: 160,
fit: BoxFit.fill,
)
: const Icon(Icons.flutter_dash),
],
),
);
}
}
'''
to keep images or any kind of data in your app u should use a database like firbase or mySql to store images then retrieve in in ur app

Flutter, image_picker showing nothing when pressed

image_picker looks fine when i use it in emulator, when it's pressed it works properly but when i install it to my phone it does nothing when i pressed the button for image_picker no camera show just nothing change.
i think it has to be some persmission" things but i don't quite understand with it
method:
var selectedImagePath = ''.obs;
getImage(ImageSource ImageSource) async {
final pickedFile = await ImagePicker().pickImage(source: ImageSource);
if (pickedFile != null) {
selectedImagePath.value = pickedFile.path;
} else {
Get.snackbar('Error', 'No Image Selected');
}
}
display:
Scaffold(
body: SafeArea(
child: Column(
children: [
Obx(
() => Container(
width: double.infinity,
height: 400,
decoration: selectedImagePath == ''
? BoxDecoration(
color: Colors.grey,
)
: BoxDecoration(
color: Colors.grey,
image: DecorationImage(
image: FileImage(
File(
selectedImagePath.value,
),
),
fit: BoxFit.cover
),
),
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
getImage(ImageSource.camera);
},
child: Text('Take a photo'),
),
ElevatedButton(
onPressed: () {
getImage(ImageSource.gallery);
},
child: Text('Take from gallery'),
),
],
),
],
),
),
);
This works for me
File? _imageFile;
Future<void> getImage(
ImageSource source) async {
XFile? pickedFile = await ImagePicker()
.pickImage(source: source);
if (pickedFile != null) {
File selected = File(pickedFile.path);
_imageFile = selected;
}
}
Let me know if it works for you.
Here is my code, I'm using Provider Library to manage it.
Step 1:
//File? _image;
String? imgString;
ImagePicker? imagePicker = ImagePicker();
Step 2: Widget Code
Future getImage() async {
final dynamic image =
await imagePicker?.pickImage(source: ImageSource.gallery);
setState(() {
if (image != null) {
YourProvider.myImage = File(image.path);
YourProvider.pickedImage = true;
imgString = YourBaseUrl + YourProvider.myImage!.path;
debugPrint("Image: $imgString");
}
});
}
Step 3: Provider
bool pickedImage = false;
File? myImage;