Hey, so I recently had a little challenge in one of my projects, I want the users to take pictures with their cameras and upload them to firebase, but the process is taking too long with multiple images and requires internet connection.
So I decided to just create my own custom actions and widget and I want to share them with you, incase anyone has a similar need and might find this useful ๐
I will be posting the code WITHOUT the default FlutterFlow imports, so it's easier on the eyes and can be easily copied into any project.
Convert Image to Base64
First I needed an option to upload a file and convert it to base64 format for easy use and conversion to Uint8list, so I made this custom action:import 'package:image_picker/image_picker.dart'; import 'dart:async'; import 'dart:io'; import 'dart:convert'; Future<String> uploadAndConvertImage() async { var bytes; // Use the ImagePicker to take a picture final XFile? pickedFile = await ImagePicker().pickImage(source: ImageSource.camera); if (pickedFile == null) { return ""; } bytes = File(pickedFile.path).readAsBytesSync(); String img64 = base64Encode(bytes); return img64; }
This code has no parameters and returns a string value which I used to store inside of a list on my page state.
Base64Image widget
So basically now, I want to display the image to my users, so they can see the pictures they've taken so far, so I had a listview which generates children based on my page state, and I created a custom widget to display the images with the base64 values I stored there:import 'dart:convert'; class Base64Image extends StatelessWidget { final double? width; final double? height; final String base64Image; Base64Image({ Key? key, this.width, this.height, required this.base64Image, }) : super(key: key); @override Widget build(BuildContext context) { // Convert the base64 string to Uint8List final decodedBytes = base64Decode(base64Image); return Image.memory( decodedBytes, width: width, height: height, fit: BoxFit.contain, ); } }
With this one, you can see it accepts one parameter, and it's a string.
uploadLocalFilesToFirestore custom action
So now, after my users have seen their pictures and are happy with the results, they'd want to upload them to the database so they can view them later, for this, I created this custom action to convert the list of base64 images into Uint8Lists and send them to my storage, there I'll get my download URLs which I add to my document and we're all done!import 'dart:convert'; import 'package:firebase_storage/firebase_storage.dart'; Future uploadLocalFilesToFirestore( List<String> locallyUploadedFiles, DocumentReference YOUR_REFERENCE, String userID, ) async { for (String file in locallyUploadedFiles) { // Convert base64 string to bytes List<int> bytes = base64.decode(file.split(',').last); // Input the bytes into a Uint8List variable Uint8List uint8List = Uint8List.fromList(bytes); // Generate unique filename String fileName = DateTime.now().millisecondsSinceEpoch.toString() + '.jpg'; // Upload file to Firebase Storage Reference storageRef = FirebaseStorage.instance.ref().child('users/$userID/uploads/$fileName'); UploadTask uploadTask = storageRef.putData(uint8List); TaskSnapshot taskSnapshot = await uploadTask.whenComplete(() => null); // Get download URL of uploaded file String downloadURL = await taskSnapshot.ref.getDownloadURL(); // Add download URL to images list of parking document in Firestore await YOUR_REFERENCE.update({ 'images': FieldValue.arrayUnion([downloadURL]), 'has_images': true, }); } }
Here I actually have 3 parameters set:
The list of strings (locallyUploadedFiles) which I also use as a conditional to run my loop and make sure all of them are uploaded properly
The reference (YOUR_REFERENCE) so I know where to add my download urls after the files are uploaded to my storage.
The user's ID so I can upload the files into the users folder and manage everything properly.
The reason I did all of this, was because I wanted to make a smoother, faster experience for my users while also allowing them to use my app while there is no internet connection, I have another custom action to check for internet connection and if it's false, it'll update all of the information into an app state which later checks every X amount of time to see if there's internet connection, once internet is available, the images are uploaded ๐
I hope someone found this useful!
If you have any questions regarding this code, let me know!