Upload files with Flutter and Firebase Cloud Storage 🔥🗃️. Learn how to pick, crop, and upload images to a cloud storage bucket. https://fireship.io/lessons/flutter-file-uploads-cloud-storage/

- Cloud Storage https://firebase.google.com/docs/storage
- Image Picker https://pub.dev/packages/image_picker
- Image Cropper https://pub.dev/packages/image_cropper


#flutter #firebase #tutorial

Don't forget to take the Flutter quizzes 🤓

iOS https://itunes.apple.com/us/app/fireship/id1462592372?mt=8
Android https://play.google.com/store/apps/details?id=io.fireship.quizapp

Upgrade to Fireship PRO at https://fireship.io/pro
Use code lORhwXd2 for 25% off your first payment.
2024-02-04T06:37:18.798Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
ce669f66-dd3b-4514-94d3-4b1973bb7708
47c2611cbbb92e8491e549d6867209d1a0a4164cce10dcd44b556497200f9cf5
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Today, we'll learn how to do 3 distinct things in Flutter.
1st, we'll capture an image from the device using the camera or photo gallery.
Next, we'll allow the user to crop, rotate, or scale the image file.
And lastly, we'll upload the file to a cloud storage bucket.
And we'll even throw in a progress bar and a pause resume button, just because it's so easy to do with Flutter and Firebase.
Base.
If you're new here, like and subscribe, and follow along with the full write up on FireShip IO.
Let's start by taking a closer look at what we'll build over the next few minutes.
You can see down here in the bottom bar we 2 icon buttons.
Tapping the camera will bring up the device camera, and the image will bring up the image gallery.
When the user selects an image, it will give us access to that file object in our dark code.
When the user taps the crop button, it will bring up the Image Cropper widget, allowing the user to manipulate the image.
And that magic is made possible by the awesome Image Cropper plugin.
And lastly, when the user taps the Upload to Firebase button, it will immediately start uploading the file to a Firebase storage bucket.
The progress indicator will show the percentage of bytes transferred while the file is uploading.
And the user can also control the state of the upload by pausing or resuming it.
So that's a lot of functionality for a single YouTube video, but I think you might be pleasantly surprised at how easy this stuff is to implement.
To get started, you'll need to have a Flutter app with Firebase installed.
I'm not going to cover the Firebase setup instructions in this video, but you can follow the pull instructions or take the full footer course as a FireShip Pro member.
Now if we go ahead and jump into the pubspec.
Yaml file, you can see we have Firebase core and storage.
These are the only 2 Firebase dependencies that you need if your only concern is uploading files to a cloud storage bucket.
But in our case, we also want the user to interact with the native device camera and image gallery, which we can do with image picker.
And then image cropper will allow the user to then manipulate the image after it's been selected.
And these plugins do have a small amount of platform specific configuration.
In.
When it comes to image picker, you'll need to go into your info plist file for iOS and add the corresponding permissions for the photo library and camera.
And for Image Cropper, there's no config for iOS, but you do need to add an activity to your Android manifest file.
And you should always refer to the official documentation when installing a new plugin in Flutter.
Now moving over to our main dart file, we'll go ahead and import these dependencies and the only other unusual thing is that we're importing dart I o and that gives us access to the file class which we'll see in use here in a couple minutes.
Now, the app we're building has 2 very different concerns with one being the image capture from the device and the other being the file upload to a remote storage bucket.
And we can easily separate these concerns in Flutter by creating 2 different stateful widgets.
The first one that we'll build is called image capture, and its responsibility is to capture an image from the gallery or camera and then allow the user to crop and resize it.
So the only piece of state on this widget is the actual file itself and the image file state will change when the user selects an image or when they crop an image.
The first method we'll define is pick image, which will either allow the user to select an image from the image gallery or capture a new image with the camera.
The image picker plugin makes this dead simple.
All we do is write a single line of code and pass it the source which will tell it whether or not to use the camera or the gallery.
And the result of this feature will be the image file which we can set as the state on this widget.
And that's all it takes to capture an image from the native device.
Now, the other way the image file state might change is if the user crops an image using the image cropper plugin and using this plugin is just as easy.
We simply pass in the source path of the existing image and it will take that existing image and create a newly cropped or modified image.
And you also have a bunch of optional properties that you can pass to the plugin as well to customize its behavior.
If the user confirms the modification, it will result in a new image file which we can then set as the image file state.
But if the user cancels the modifications, the value will be null, in which case we can use Dart's null aware double question mark operator to return the existing image file.
Now, at this point, you might be wondering how we're getting so much amazing functionality with only a few lines of code.
The magic is made possible by the Image Cropper plugin, which itself is a wrapper for native libraries like u crop and tocropviewcontroller on iOS.
Now that we have the logic in place to capture and crop an image, let's move on to the UI.
We have a couple of buttons down here at the bottom which allow the user to either capture from the camera or from the gallery.
And then once an image is selected, they can either crop it or clear it by simply setting the image file to null.
We can implement the buttons down at the bottom by setting up a scaffold and then defining a bottom navigation bar as a bottom app bar.
Then we'll create a row with a couple of icon buttons in it and each icon button will call the same pick image method just with a different argument for the source which can either be the camera or the gallery.
From there, we'll move on to the body of the scaffold which we'll define as a list view and then it will have children if the image file does not equal null.
If we have an image file, then we'll go ahead and show it in the UI with the image widget and then we'll display a row with some buttons that allow the user to crop that image or to clear it from the UI.
And that code can be implemented by simply attaching the methods that we defined earlier as the on pressed event handlers for these buttons.
Now, the last widget that we'll add here is called Uploader, which is a custom widget that we'll define next, and we'll pass the image file down to it as an input property.
The responsibility of the uploader is to take the raw file and then create a Firebase storage upload task.
One of the benefits of having this in its own widget is that you could potentially loop over it to create multiple upload tasks at once, which would allow you to upload multiple files concurrently.
We can pass the file object from the parent to the child by setting it as a property here and then adding it to the constructor.
From there, we'll go down to the state and we'll instantiate Firebase Storage.
You can think of this as a service that allows you to interact with a cloud storage bucket to both upload and download files.
You just need to pass it a storage bucket argument with the bucket URI, which you can find on the Firebase console.
And while we're here in the console, I should also point out that you should have security rules disabled for the storage bucket just so we can freely upload files for this demo.
Now back in our code, we'll set a property for the storage upload task.
This is the single most important part of the feature because it provides the current state of the upload as well as the event stream that we can listen to to update the UI.
When you instantiate a storage upload task, it will immediately start uploading that file to storage.
So So we'll go ahead and create a start upload method that allows the user to click a button to start the upload lazily.
In addition to the file, you also need to have a path to upload that file to.
A storage bucket is no different than the file system on your computer, and that means only one file can exist at a given path at a time.
Many apps will generate a unique ID for each individual upload, or a quick and dirty way to do it is just to use date, time, now.
So now that we have the file path string and the raw file object, We can make a reference to the storage bucket and then call child with the file path and then call put file with the file object.
And that will return us with a Firebase storage upload task.
And that's actually all it takes to upload a file to storage, but you'll very likely want to give the user a progress indicator and maybe the option to pause or cancel the upload as well.
In the build method, we'll go ahead and start with a conditional and if the upload task is null, then we'll display a button that allows the user to start the upload.
So tapping this button will create an instance of an upload task, which will immediately start transmitting that file to your Firebase storage bucket.
The upload task object also exposes a stream of storage task events, which we can pass to a StreamBuilder to update the progress bar.
So we'll use a storage task event as the generic type to the StreamBuilder and we'll set the Stream property as the upload task event.
The storage task event object contains useful information like the number of bytes transferred and the total bytes in the file so you can calculate the total progress of the upload.
And you can expect the stream to emit a new event every couple 100 milliseconds or so.
Now, when it comes to a progress bar, we'll be looking for a number that ranges from 0 to 1.
And we can obtain the information to make that calculation from the event.
It contains the number of bytes transferred to storage thus far along with a bunch of other metadata that you might find useful.
In our case here, we can get the progress percent by dividing the total byte count by the bytes transferred.
Now, one of the really cool things about Firebase is that it makes it easy for the user to pause, cancel, and resume and upload.
And we can control which parts of the UI to show based on the state of the upload task.
That means you can set up some conditional logic and then use the different states like sold as complete, is in progress, etcetera.
In addition to the state, the upload task also contains methods for the user to manually control the upload.
For example, if the upload task is paused, then we'll go ahead and create a button that allows them to resume it.
And then we can do the exact opposite.
If the upload task is in progress, then we'll provide a button to pause it.
And last but not least, we'll want to show the user some kind of progress indicator.
An easy way to do this is with the built in linear progress indicator and we can use the progress percent that we figured out earlier as its value.
And for an added touch, we'll go ahead and display the progress percent as a string as well.
And that's all it takes to build a full stack file upload feature with Flutter.
I'm gonna go ahead and wrap things up there.
If this video helped you, please like and scribe.
And if you wanna learn more about Flutter and Firebase, consider enrolling in the full Flutter course or becoming a pro member at Fireship IO.
Thanks for watching, and I will talk to you soon.

Speaker 0: Today, we'll learn how to do 3 distinct things in Flutter. 1st, we'll capture an image from the device using the camera or photo gallery. Next, we'll allow the user to crop, rotate, or scale the image file. And lastly, we'll upload the file to a cloud storage bucket. And we'll even throw in a progress bar and a pause resume button, just because it's so easy to do with Flutter and Firebase.

Base. If you're new here, like and subscribe, and follow along with the full write up on FireShip IO. Let's start by taking a closer look at what we'll build over the next few minutes. You can see down here in the bottom bar we 2 icon buttons. Tapping the camera will bring up the device camera, and the image will bring up the image gallery.

When the user selects an image, it will give us access to that file object in our dark code. When the user taps the crop button, it will bring up the Image Cropper widget, allowing the user to manipulate the image. And that magic is made possible by the awesome Image Cropper plugin. And lastly, when the user taps the Upload to Firebase button, it will immediately start uploading the file to a Firebase storage bucket. The progress indicator will show the percentage of bytes transferred while the file is uploading.

And the user can also control the state of the upload by pausing or resuming it. So that's a lot of functionality for a single YouTube video, but I think you might be pleasantly surprised at how easy this stuff is to implement. To get started, you'll need to have a Flutter app with Firebase installed. I'm not going to cover the Firebase setup instructions in this video, but you can follow the pull instructions or take the full footer course as a FireShip Pro member. Now if we go ahead and jump into the pubspec.

Yaml file, you can see we have Firebase core and storage. These are the only 2 Firebase dependencies that you need if your only concern is uploading files to a cloud storage bucket. But in our case, we also want the user to interact with the native device camera and image gallery, which we can do with image picker. And then image cropper will allow the user to then manipulate the image after it's been selected. And these plugins do have a small amount of platform specific configuration.

In. When it comes to image picker, you'll need to go into your info plist file for iOS and add the corresponding permissions for the photo library and camera. And for Image Cropper, there's no config for iOS, but you do need to add an activity to your Android manifest file. And you should always refer to the official documentation when installing a new plugin in Flutter. Now moving over to our main dart file, we'll go ahead and import these dependencies and the only other unusual thing is that we're importing dart I o and that gives us access to the file class which we'll see in use here in a couple minutes.

Now, the app we're building has 2 very different concerns with one being the image capture from the device and the other being the file upload to a remote storage bucket. And we can easily separate these concerns in Flutter by creating 2 different stateful widgets. The first one that we'll build is called image capture, and its responsibility is to capture an image from the gallery or camera and then allow the user to crop and resize it. So the only piece of state on this widget is the actual file itself and the image file state will change when the user selects an image or when they crop an image. The first method we'll define is pick image, which will either allow the user to select an image from the image gallery or capture a new image with the camera.

The image picker plugin makes this dead simple. All we do is write a single line of code and pass it the source which will tell it whether or not to use the camera or the gallery. And the result of this feature will be the image file which we can set as the state on this widget. And that's all it takes to capture an image from the native device. Now, the other way the image file state might change is if the user crops an image using the image cropper plugin and using this plugin is just as easy.

We simply pass in the source path of the existing image and it will take that existing image and create a newly cropped or modified image. And you also have a bunch of optional properties that you can pass to the plugin as well to customize its behavior. If the user confirms the modification, it will result in a new image file which we can then set as the image file state. But if the user cancels the modifications, the value will be null, in which case we can use Dart's null aware double question mark operator to return the existing image file. Now, at this point, you might be wondering how we're getting so much amazing functionality with only a few lines of code.

The magic is made possible by the Image Cropper plugin, which itself is a wrapper for native libraries like u crop and tocropviewcontroller on iOS. Now that we have the logic in place to capture and crop an image, let's move on to the UI. We have a couple of buttons down here at the bottom which allow the user to either capture from the camera or from the gallery. And then once an image is selected, they can either crop it or clear it by simply setting the image file to null. We can implement the buttons down at the bottom by setting up a scaffold and then defining a bottom navigation bar as a bottom app bar.

Then we'll create a row with a couple of icon buttons in it and each icon button will call the same pick image method just with a different argument for the source which can either be the camera or the gallery. From there, we'll move on to the body of the scaffold which we'll define as a list view and then it will have children if the image file does not equal null. If we have an image file, then we'll go ahead and show it in the UI with the image widget and then we'll display a row with some buttons that allow the user to crop that image or to clear it from the UI. And that code can be implemented by simply attaching the methods that we defined earlier as the on pressed event handlers for these buttons. Now, the last widget that we'll add here is called Uploader, which is a custom widget that we'll define next, and we'll pass the image file down to it as an input property.

The responsibility of the uploader is to take the raw file and then create a Firebase storage upload task. One of the benefits of having this in its own widget is that you could potentially loop over it to create multiple upload tasks at once, which would allow you to upload multiple files concurrently. We can pass the file object from the parent to the child by setting it as a property here and then adding it to the constructor. From there, we'll go down to the state and we'll instantiate Firebase Storage. You can think of this as a service that allows you to interact with a cloud storage bucket to both upload and download files.

You just need to pass it a storage bucket argument with the bucket URI, which you can find on the Firebase console. And while we're here in the console, I should also point out that you should have security rules disabled for the storage bucket just so we can freely upload files for this demo. Now back in our code, we'll set a property for the storage upload task. This is the single most important part of the feature because it provides the current state of the upload as well as the event stream that we can listen to to update the UI. When you instantiate a storage upload task, it will immediately start uploading that file to storage.

So So we'll go ahead and create a start upload method that allows the user to click a button to start the upload lazily. In addition to the file, you also need to have a path to upload that file to. A storage bucket is no different than the file system on your computer, and that means only one file can exist at a given path at a time. Many apps will generate a unique ID for each individual upload, or a quick and dirty way to do it is just to use date, time, now. So now that we have the file path string and the raw file object, We can make a reference to the storage bucket and then call child with the file path and then call put file with the file object.

And that will return us with a Firebase storage upload task. And that's actually all it takes to upload a file to storage, but you'll very likely want to give the user a progress indicator and maybe the option to pause or cancel the upload as well. In the build method, we'll go ahead and start with a conditional and if the upload task is null, then we'll display a button that allows the user to start the upload. So tapping this button will create an instance of an upload task, which will immediately start transmitting that file to your Firebase storage bucket. The upload task object also exposes a stream of storage task events, which we can pass to a StreamBuilder to update the progress bar.

So we'll use a storage task event as the generic type to the StreamBuilder and we'll set the Stream property as the upload task event. The storage task event object contains useful information like the number of bytes transferred and the total bytes in the file so you can calculate the total progress of the upload. And you can expect the stream to emit a new event every couple 100 milliseconds or so. Now, when it comes to a progress bar, we'll be looking for a number that ranges from 0 to 1. And we can obtain the information to make that calculation from the event.

It contains the number of bytes transferred to storage thus far along with a bunch of other metadata that you might find useful. In our case here, we can get the progress percent by dividing the total byte count by the bytes transferred. Now, one of the really cool things about Firebase is that it makes it easy for the user to pause, cancel, and resume and upload. And we can control which parts of the UI to show based on the state of the upload task. That means you can set up some conditional logic and then use the different states like sold as complete, is in progress, etcetera.

In addition to the state, the upload task also contains methods for the user to manually control the upload. For example, if the upload task is paused, then we'll go ahead and create a button that allows them to resume it. And then we can do the exact opposite. If the upload task is in progress, then we'll provide a button to pause it. And last but not least, we'll want to show the user some kind of progress indicator.

An easy way to do this is with the built in linear progress indicator and we can use the progress percent that we figured out earlier as its value. And for an added touch, we'll go ahead and display the progress percent as a string as well. And that's all it takes to build a full stack file upload feature with Flutter. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe.

And if you wanna learn more about Flutter and Firebase, consider enrolling in the full Flutter course or becoming a pro member at Fireship IO. Thanks for watching, and I will talk to you soon.
Today, we'll learn how to do 3 distinct things in Flutter. 1st, we'll capture an image from the device using the camera or photo gallery. Next, we'll allow the user to crop, rotate, or scale the image file. And lastly, we'll upload the file to a cloud storage bucket. And we'll even throw in a progress bar and a pause resume button, just because it's so easy to do with Flutter and Firebase.
animation
Base. If you're new here, like and subscribe, and follow along with the full write up on FireShip IO. Let's start by taking a closer look at what we'll build over the next few minutes.
You can see down here in the bottom bar we 2 icon buttons. Tapping the camera will bring up the device camera, and the image will bring up the image gallery. When the user selects an image, it will give us access to that file object in our dark code.
photography
multimedia
When the user taps the crop button, it will bring up the Image Cropper widget, allowing the user to manipulate the image. And that magic is made possible by the awesome Image Cropper plugin. And lastly, when the user taps the Upload to Firebase button, it will immediately start uploading the file to a Firebase storage bucket.
The progress indicator will show the percentage of bytes transferred while the file is uploading. And the user can also control the state of the upload by pausing or resuming it. So that's a lot of functionality for a single YouTube video, but I think you might be pleasantly surprised at how easy this stuff is to implement. To get started, you'll need to have a Flutter app with Firebase installed. I'm not going to cover the Firebase setup instructions in this video, but you can follow the pull instructions or take the full footer course as a FireShip Pro member.
youtube
streaming
multimedia
video gaming
Now if we go ahead and jump into the pubspec. Yaml file, you can see we have Firebase core and storage. These are the only 2 Firebase dependencies that you need if your only concern is uploading files to a cloud storage bucket.
But in our case, we also want the user to interact with the native device camera and image gallery, which we can do with image picker. And then image cropper will allow the user to then manipulate the image after it's been selected. And these plugins do have a small amount of platform specific configuration. In. When it comes to image picker, you'll need to go into your info plist file for iOS and add the corresponding permissions for the photo library and camera.
photography
And for Image Cropper, there's no config for iOS, but you do need to add an activity to your Android manifest file. And you should always refer to the official documentation when installing a new plugin in Flutter. Now moving over to our main dart file, we'll go ahead and import these dependencies and the only other unusual thing is that we're importing dart I o and that gives us access to the file class which we'll see in use here in a couple minutes.
Now, the app we're building has 2 very different concerns with one being the image capture from the device and the other being the file upload to a remote storage bucket. And we can easily separate these concerns in Flutter by creating 2 different stateful widgets. The first one that we'll build is called image capture, and its responsibility is to capture an image from the gallery or camera and then allow the user to crop and resize it. So the only piece of state on this widget is the actual file itself and the image file state will change when the user selects an image or when they crop an image.
animation
multimedia
visualization
The first method we'll define is pick image, which will either allow the user to select an image from the image gallery or capture a new image with the camera. The image picker plugin makes this dead simple. All we do is write a single line of code and pass it the source which will tell it whether or not to use the camera or the gallery. And the result of this feature will be the image file which we can set as the state on this widget. And that's all it takes to capture an image from the native device. Now, the other way the image file state might change is if the user crops an image using the image cropper plugin and using this plugin is just as easy. We simply pass in the source path of the existing image and it will take that existing image and create a newly cropped or modified image.
photography
And you also have a bunch of optional properties that you can pass to the plugin as well to customize its behavior. If the user confirms the modification, it will result in a new image file which we can then set as the image file state. But if the user cancels the modifications, the value will be null, in which case we can use Dart's null aware double question mark operator to return the existing image file. Now, at this point, you might be wondering how we're getting so much amazing functionality with only a few lines of code. The magic is made possible by the Image Cropper plugin, which itself is a wrapper for native libraries like u crop and tocropviewcontroller on iOS.
Now that we have the logic in place to capture and crop an image, let's move on to the UI. We have a couple of buttons down here at the bottom which allow the user to either capture from the camera or from the gallery. And then once an image is selected, they can either crop it or clear it by simply setting the image file to null.
photography
We can implement the buttons down at the bottom by setting up a scaffold and then defining a bottom navigation bar as a bottom app bar. Then we'll create a row with a couple of icon buttons in it and each icon button will call the same pick image method just with a different argument for the source which can either be the camera or the gallery.
From there, we'll move on to the body of the scaffold which we'll define as a list view and then it will have children if the image file does not equal null. If we have an image file, then we'll go ahead and show it in the UI with the image widget and then we'll display a row with some buttons that allow the user to crop that image or to clear it from the UI. And that code can be implemented by simply attaching the methods that we defined earlier as the on pressed event handlers for these buttons.
visualization
graphic design
animation
Now, the last widget that we'll add here is called Uploader, which is a custom widget that we'll define next, and we'll pass the image file down to it as an input property. The responsibility of the uploader is to take the raw file and then create a Firebase storage upload task. One of the benefits of having this in its own widget is that you could potentially loop over it to create multiple upload tasks at once, which would allow you to upload multiple files concurrently. We can pass the file object from the parent to the child by setting it as a property here and then adding it to the constructor. From there, we'll go down to the state and we'll instantiate Firebase Storage. You can think of this as a service that allows you to interact with a cloud storage bucket to both upload and download files. You just need to pass it a storage bucket argument with the bucket URI, which you can find on the Firebase console. And while we're here in the console, I should also point out that you should have security rules disabled for the storage bucket just so we can freely upload files for this demo. Now back in our code, we'll set a property for the storage upload task. This is the single most important part of the feature because it provides the current state of the upload as well as the event stream that we can listen to to update the UI. When you instantiate a storage upload task, it will immediately start uploading that file to storage. So So we'll go ahead and create a start upload method that allows the user to click a button to start the upload lazily. In addition to the file, you also need to have a path to upload that file to. A storage bucket is no different than the file system on your computer, and that means only one file can exist at a given path at a time. Many apps will generate a unique ID for each individual upload, or a quick and dirty way to do it is just to use date, time, now. So now that we have the file path string and the raw file object, We can make a reference to the storage bucket and then call child with the file path and then call put file with the file object. And that will return us with a Firebase storage upload task. And that's actually all it takes to upload a file to storage, but you'll very likely want to give the user a progress indicator and maybe the option to pause or cancel the upload as well. In the build method, we'll go ahead and start with a conditional and if the upload task is null, then we'll display a button that allows the user to start the upload. So tapping this button will create an instance of an upload task, which will immediately start transmitting that file to your Firebase storage bucket. The upload task object also exposes a stream of storage task events, which we can pass to a StreamBuilder to update the progress bar. So we'll use a storage task event as the generic type to the StreamBuilder and we'll set the Stream property as the upload task event.
The storage task event object contains useful information like the number of bytes transferred and the total bytes in the file so you can calculate the total progress of the upload. And you can expect the stream to emit a new event every couple 100 milliseconds or so. Now, when it comes to a progress bar, we'll be looking for a number that ranges from 0 to 1.
data
And we can obtain the information to make that calculation from the event. It contains the number of bytes transferred to storage thus far along with a bunch of other metadata that you might find useful. In our case here, we can get the progress percent by dividing the total byte count by the bytes transferred.
data
Now, one of the really cool things about Firebase is that it makes it easy for the user to pause, cancel, and resume and upload. And we can control which parts of the UI to show based on the state of the upload task. That means you can set up some conditional logic and then use the different states like sold as complete, is in progress, etcetera. In addition to the state, the upload task also contains methods for the user to manually control the upload. For example, if the upload task is paused, then we'll go ahead and create a button that allows them to resume it. And then we can do the exact opposite. If the upload task is in progress, then we'll provide a button to pause it. And last but not least, we'll want to show the user some kind of progress indicator. An easy way to do this is with the built in linear progress indicator and we can use the progress percent that we figured out earlier as its value. And for an added touch, we'll go ahead and display the progress percent as a string as well. And that's all it takes to build a full stack file upload feature with Flutter.
I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe. And if you wanna learn more about Flutter and Firebase, consider enrolling in the full Flutter course or becoming a pro member at Fireship IO. Thanks for watching, and I will talk to you soon.
youtube
Today, we'll learn how to do 3 distinct things in Flutter. 1st, we'll capture an image from the device using the camera or photo gallery. Next, we'll allow the user to crop, rotate, or scale the image file. And lastly, we'll upload the file to a cloud storage bucket. And we'll even throw in a progress bar and a pause resume button, just because it's so easy to do with Flutter and Firebase. Base. If you're new here, like and subscribe, and follow along with the full write up on FireShip IO. Let's start by taking a closer look at what we'll build over the next few minutes. You can see down here in the bottom bar we 2 icon buttons. Tapping the camera will bring up the device camera, and the image will bring up the image gallery. When the user selects an image, it will give us access to that file object in our dark code. When the user taps the crop button, it will bring up the Image Cropper widget, allowing the user to manipulate the image. And that magic is made possible by the awesome Image Cropper plugin. And lastly, when the user taps the Upload to Firebase button, it will immediately start uploading the file to a Firebase storage bucket. The progress indicator will show the percentage of bytes transferred while the file is uploading. And the user can also control the state of the upload by pausing or resuming it. So that's a lot of functionality for a single YouTube video, but I think you might be pleasantly surprised at how easy this stuff is to implement. To get started, you'll need to have a Flutter app with Firebase installed. I'm not going to cover the Firebase setup instructions in this video, but you can follow the pull instructions or take the full footer course as a FireShip Pro member. Now if we go ahead and jump into the pubspec. Yaml file, you can see we have Firebase core and storage. These are the only 2 Firebase dependencies that you need if your only concern is uploading files to a cloud storage bucket. But in our case, we also want the user to interact with the native device camera and image gallery, which we can do with image picker. And then image cropper will allow the user to then manipulate the image after it's been selected. And these plugins do have a small amount of platform specific configuration. In. When it comes to image picker, you'll need to go into your info plist file for iOS and add the corresponding permissions for the photo library and camera. And for Image Cropper, there's no config for iOS, but you do need to add an activity to your Android manifest file. And you should always refer to the official documentation when installing a new plugin in Flutter. Now moving over to our main dart file, we'll go ahead and import these dependencies and the only other unusual thing is that we're importing dart I o and that gives us access to the file class which we'll see in use here in a couple minutes. Now, the app we're building has 2 very different concerns with one being the image capture from the device and the other being the file upload to a remote storage bucket. And we can easily separate these concerns in Flutter by creating 2 different stateful widgets. The first one that we'll build is called image capture, and its responsibility is to capture an image from the gallery or camera and then allow the user to crop and resize it. So the only piece of state on this widget is the actual file itself and the image file state will change when the user selects an image or when they crop an image. The first method we'll define is pick image, which will either allow the user to select an image from the image gallery or capture a new image with the camera. The image picker plugin makes this dead simple. All we do is write a single line of code and pass it the source which will tell it whether or not to use the camera or the gallery. And the result of this feature will be the image file which we can set as the state on this widget. And that's all it takes to capture an image from the native device. Now, the other way the image file state might change is if the user crops an image using the image cropper plugin and using this plugin is just as easy. We simply pass in the source path of the existing image and it will take that existing image and create a newly cropped or modified image. And you also have a bunch of optional properties that you can pass to the plugin as well to customize its behavior. If the user confirms the modification, it will result in a new image file which we can then set as the image file state. But if the user cancels the modifications, the value will be null, in which case we can use Dart's null aware double question mark operator to return the existing image file. Now, at this point, you might be wondering how we're getting so much amazing functionality with only a few lines of code. The magic is made possible by the Image Cropper plugin, which itself is a wrapper for native libraries like u crop and tocropviewcontroller on iOS. Now that we have the logic in place to capture and crop an image, let's move on to the UI. We have a couple of buttons down here at the bottom which allow the user to either capture from the camera or from the gallery. And then once an image is selected, they can either crop it or clear it by simply setting the image file to null. We can implement the buttons down at the bottom by setting up a scaffold and then defining a bottom navigation bar as a bottom app bar. Then we'll create a row with a couple of icon buttons in it and each icon button will call the same pick image method just with a different argument for the source which can either be the camera or the gallery. From there, we'll move on to the body of the scaffold which we'll define as a list view and then it will have children if the image file does not equal null. If we have an image file, then we'll go ahead and show it in the UI with the image widget and then we'll display a row with some buttons that allow the user to crop that image or to clear it from the UI. And that code can be implemented by simply attaching the methods that we defined earlier as the on pressed event handlers for these buttons. Now, the last widget that we'll add here is called Uploader, which is a custom widget that we'll define next, and we'll pass the image file down to it as an input property. The responsibility of the uploader is to take the raw file and then create a Firebase storage upload task. One of the benefits of having this in its own widget is that you could potentially loop over it to create multiple upload tasks at once, which would allow you to upload multiple files concurrently. We can pass the file object from the parent to the child by setting it as a property here and then adding it to the constructor. From there, we'll go down to the state and we'll instantiate Firebase Storage. You can think of this as a service that allows you to interact with a cloud storage bucket to both upload and download files. You just need to pass it a storage bucket argument with the bucket URI, which you can find on the Firebase console. And while we're here in the console, I should also point out that you should have security rules disabled for the storage bucket just so we can freely upload files for this demo. Now back in our code, we'll set a property for the storage upload task. This is the single most important part of the feature because it provides the current state of the upload as well as the event stream that we can listen to to update the UI. When you instantiate a storage upload task, it will immediately start uploading that file to storage. So So we'll go ahead and create a start upload method that allows the user to click a button to start the upload lazily. In addition to the file, you also need to have a path to upload that file to. A storage bucket is no different than the file system on your computer, and that means only one file can exist at a given path at a time. Many apps will generate a unique ID for each individual upload, or a quick and dirty way to do it is just to use date, time, now. So now that we have the file path string and the raw file object, We can make a reference to the storage bucket and then call child with the file path and then call put file with the file object. And that will return us with a Firebase storage upload task. And that's actually all it takes to upload a file to storage, but you'll very likely want to give the user a progress indicator and maybe the option to pause or cancel the upload as well. In the build method, we'll go ahead and start with a conditional and if the upload task is null, then we'll display a button that allows the user to start the upload. So tapping this button will create an instance of an upload task, which will immediately start transmitting that file to your Firebase storage bucket. The upload task object also exposes a stream of storage task events, which we can pass to a StreamBuilder to update the progress bar. So we'll use a storage task event as the generic type to the StreamBuilder and we'll set the Stream property as the upload task event. The storage task event object contains useful information like the number of bytes transferred and the total bytes in the file so you can calculate the total progress of the upload. And you can expect the stream to emit a new event every couple 100 milliseconds or so. Now, when it comes to a progress bar, we'll be looking for a number that ranges from 0 to 1. And we can obtain the information to make that calculation from the event. It contains the number of bytes transferred to storage thus far along with a bunch of other metadata that you might find useful. In our case here, we can get the progress percent by dividing the total byte count by the bytes transferred. Now, one of the really cool things about Firebase is that it makes it easy for the user to pause, cancel, and resume and upload. And we can control which parts of the UI to show based on the state of the upload task. That means you can set up some conditional logic and then use the different states like sold as complete, is in progress, etcetera. In addition to the state, the upload task also contains methods for the user to manually control the upload. For example, if the upload task is paused, then we'll go ahead and create a button that allows them to resume it. And then we can do the exact opposite. If the upload task is in progress, then we'll provide a button to pause it. And last but not least, we'll want to show the user some kind of progress indicator. An easy way to do this is with the built in linear progress indicator and we can use the progress percent that we figured out earlier as its value. And for an added touch, we'll go ahead and display the progress percent as a string as well. And that's all it takes to build a full stack file upload feature with Flutter. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe. And if you wanna learn more about Flutter and Firebase, consider enrolling in the full Flutter course or becoming a pro member at Fireship IO. Thanks for watching, and I will talk to you soon.
Today,
today
we'll
we'll
learn
learn
how
how
to
to
do
do
3
3
distinct
distinct
things
things
in
in
Flutter.
flutter
1st,
1st
we'll
we'll
capture
capture
an
an
image
image
from
from
the
the
device
device
using
using
the
the
camera
camera
or
or
photo
photo
gallery.
gallery
Next,
next
we'll
we'll
allow
allow
the
the
user
user
to
to
crop,
crop
rotate,
rotate
or
or
scale
scale
the
the
image
image
file.
file
And
and
lastly,
lastly
we'll
we'll
upload
upload
the
the
file
file
to
to
a
a
cloud
cloud
storage
storage
bucket.
bucket
And
and
we'll
we'll
even
even
throw
throw
in
in
a
a
progress
progress
bar
bar
and
and
a
a
pause
pause
resume
resume
button,
button
just
just
because
because
it's
it's
so
so
easy
easy
to
to
do
do
with
with
Flutter
flutter
and
and
Firebase.
firebase
Base.
base
If
if
you're
you're
new
new
here,
here
like
like
and
and
subscribe,
subscribe
and
and
follow
follow
along
along
with
with
the
the
full
full
write
write
up
up
on
on
FireShip
fireship
IO.
io
Let's
let's
start
start
by
by
taking
taking
a
a
closer
closer
look
look
at
at
what
what
we'll
we'll
build
build
over
over
the
the
next
next
few
few
minutes.
minutes
You
you
can
can
see
see
down
down
here
here
in
in
the
the
bottom
bottom
bar
bar
we
we
2
2
icon
icon
buttons.
buttons
Tapping
tapping
the
the
camera
camera
will
will
bring
bring
up
up
the
the
device
device
camera,
camera
and
and
the
the
image
image
will
will
bring
bring
up
up
the
the
image
image
gallery.
gallery
When
when
the
the
user
user
selects
selects
an
an
image,
image
it
it
will
will
give
give
us
us
access
access
to
to
that
that
file
file
object
object
in
in
our
our
dark
dark
code.
code
When
when
the
the
user
user
taps
taps
the
the
crop
crop
button,
button
it
it
will
will
bring
bring
up
up
the
the
Image
image
Cropper
cropper
widget,
widget
allowing
allowing
the
the
user
user
to
to
manipulate
manipulate
the
the
image.
image
And
and
that
that
magic
magic
is
is
made
made
possible
possible
by
by
the
the
awesome
awesome
Image
image
Cropper
cropper
plugin.
plugin
And
and
lastly,
lastly
when
when
the
the
user
user
taps
taps
the
the
Upload
upload
to
to
Firebase
firebase
button,
button
it
it
will
will
immediately
immediately
start
start
uploading
uploading
the
the
file
file
to
to
a
a
Firebase
firebase
storage
storage
bucket.
bucket
The
the
progress
progress
indicator
indicator
will
will
show
show
the
the
percentage
percentage
of
of
bytes
bytes
transferred
transferred
while
while
the
the
file
file
is
is
uploading.
uploading
And
and
the
the
user
user
can
can
also
also
control
control
the
the
state
state
of
of
the
the
upload
upload
by
by
pausing
pausing
or
or
resuming
resuming
it.
it
So
so
that's
that's
a
a
lot
lot
of
of
functionality
functionality
for
for
a
a
single
single
YouTube
youtube
video,
video
but
but
I
i
think
think
you
you
might
might
be
be
pleasantly
pleasantly
surprised
surprised
at
at
how
how
easy
easy
this
this
stuff
stuff
is
is
to
to
implement.
implement
To
to
get
get
started,
started
you'll
you'll
need
need
to
to
have
have
a
a
Flutter
flutter
app
app
with
with
Firebase
firebase
installed.
installed
I'm
i'm
not
not
going
going
to
to
cover
cover
the
the
Firebase
firebase
setup
setup
instructions
instructions
in
in
this
this
video,
video
but
but
you
you
can
can
follow
follow
the
the
pull
pull
instructions
instructions
or
or
take
take
the
the
full
full
footer
footer
course
course
as
as
a
a
FireShip
fireship
Pro
pro
member.
member
Now
now
if
if
we
we
go
go
ahead
ahead
and
and
jump
jump
into
into
the
the
pubspec.
pubspec
Yaml
yaml
file,
file
you
you
can
can
see
see
we
we
have
have
Firebase
firebase
core
core
and
and
storage.
storage
These
these
are
are
the
the
only
only
2
2
Firebase
firebase
dependencies
dependencies
that
that
you
you
need
need
if
if
your
your
only
only
concern
concern
is
is
uploading
uploading
files
files
to
to
a
a
cloud
cloud
storage
storage
bucket.
bucket
But
but
in
in
our
our
case,
case
we
we
also
also
want
want
the
the
user
user
to
to
interact
interact
with
with
the
the
native
native
device
device
camera
camera
and
and
image
image
gallery,
gallery
which
which
we
we
can
can
do
do
with
with
image
image
picker.
picker
And
and
then
then
image
image
cropper
cropper
will
will
allow
allow
the
the
user
user
to
to
then
then
manipulate
manipulate
the
the
image
image
after
after
it's
it's
been
been
selected.
selected
And
and
these
these
plugins
plugins
do
do
have
have
a
a
small
small
amount
amount
of
of
platform
platform
specific
specific
configuration.
configuration
In.
in
When
when
it
it
comes
comes
to
to
image
image
picker,
picker
you'll
you'll
need
need
to
to
go
go
into
into
your
your
info
info
plist
plist
file
file
for
for
iOS
ios
and
and
add
add
the
the
corresponding
corresponding
permissions
permissions
for
for
the
the
photo
photo
library
library
and
and
camera.
camera
And
and
for
for
Image
image
Cropper,
cropper
there's
there's
no
no
config
config
for
for
iOS,
ios
but
but
you
you
do
do
need
need
to
to
add
add
an
an
activity
activity
to
to
your
your
Android
android
manifest
manifest
file.
file
And
and
you
you
should
should
always
always
refer
refer
to
to
the
the
official
official
documentation
documentation
when
when
installing
installing
a
a
new
new
plugin
plugin
in
in
Flutter.
flutter
Now
now
moving
moving
over
over
to
to
our
our
main
main
dart
dart
file,
file
we'll
we'll
go
go
ahead
ahead
and
and
import
import
these
these
dependencies
dependencies
and
and
the
the
only
only
other
other
unusual
unusual
thing
thing
is
is
that
that
we're
we're
importing
importing
dart
dart
I
i
o
o
and
and
that
that
gives
gives
us
us
access
access
to
to
the
the
file
file
class
class
which
which
we'll
we'll
see
see
in
in
use
use
here
here
in
in
a
a
couple
couple
minutes.
minutes
Now,
now
the
the
app
app
we're
we're
building
building
has
has
2
2
very
very
different
different
concerns
concerns
with
with
one
one
being
being
the
the
image
image
capture
capture
from
from
the
the
device
device
and
and
the
the
other
other
being
being
the
the
file
file
upload
upload
to
to
a
a
remote
remote
storage
storage
bucket.
bucket
And
and
we
we
can
can
easily
easily
separate
separate
these
these
concerns
concerns
in
in
Flutter
flutter
by
by
creating
creating
2
2
different
different
stateful
stateful
widgets.
widgets
The
the
first
first
one
one
that
that
we'll
we'll
build
build
is
is
called
called
image
image
capture,
capture
and
and
its
its
responsibility
responsibility
is
is
to
to
capture
capture
an
an
image
image
from
from
the
the
gallery
gallery
or
or
camera
camera
and
and
then
then
allow
allow
the
the
user
user
to
to
crop
crop
and
and
resize
resize
it.
it
So
so
the
the
only
only
piece
piece
of
of
state
state
on
on
this
this
widget
widget
is
is
the
the
actual
actual
file
file
itself
itself
and
and
the
the
image
image
file
file
state
state
will
will
change
change
when
when
the
the
user
user
selects
selects
an
an
image
image
or
or
when
when
they
they
crop
crop
an
an
image.
image
The
the
first
first
method
method
we'll
we'll
define
define
is
is
pick
pick
image,
image
which
which
will
will
either
either
allow
allow
the
the
user
user
to
to
select
select
an
an
image
image
from
from
the
the
image
image
gallery
gallery
or
or
capture
capture
a
a
new
new
image
image
with
with
the
the
camera.
camera
The
the
image
image
picker
picker
plugin
plugin
makes
makes
this
this
dead
dead
simple.
simple
All
all
we
we
do
do
is
is
write
write
a
a
single
single
line
line
of
of
code
code
and
and
pass
pass
it
it
the
the
source
source
which
which
will
will
tell
tell
it
it
whether
whether
or
or
not
not
to
to
use
use
the
the
camera
camera
or
or
the
the
gallery.
gallery
And
and
the
the
result
result
of
of
this
this
feature
feature
will
will
be
be
the
the
image
image
file
file
which
which
we
we
can
can
set
set
as
as
the
the
state
state
on
on
this
this
widget.
widget
And
and
that's
that's
all
all
it
it
takes
takes
to
to
capture
capture
an
an
image
image
from
from
the
the
native
native
device.
device
Now,
now
the
the
other
other
way
way
the
the
image
image
file
file
state
state
might
might
change
change
is
is
if
if
the
the
user
user
crops
crops
an
an
image
image
using
using
the
the
image
image
cropper
cropper
plugin
plugin
and
and
using
using
this
this
plugin
plugin
is
is
just
just
as
as
easy.
easy
We
we
simply
simply
pass
pass
in
in
the
the
source
source
path
path
of
of
the
the
existing
existing
image
image
and
and
it
it
will
will
take
take
that
that
existing
existing
image
image
and
and
create
create
a
a
newly
newly
cropped
cropped
or
or
modified
modified
image.
image
And
and
you
you
also
also
have
have
a
a
bunch
bunch
of
of
optional
optional
properties
properties
that
that
you
you
can
can
pass
pass
to
to
the
the
plugin
plugin
as
as
well
well
to
to
customize
customize
its
its
behavior.
behavior
If
if
the
the
user
user
confirms
confirms
the
the
modification,
modification
it
it
will
will
result
result
in
in
a
a
new
new
image
image
file
file
which
which
we
we
can
can
then
then
set
set
as
as
the
the
image
image
file
file
state.
state
But
but
if
if
the
the
user
user
cancels
cancels
the
the
modifications,
modifications
the
the
value
value
will
will
be
be
null,
null
in
in
which
which
case
case
we
we
can
can
use
use
Dart's
dart's
null
null
aware
aware
double
double
question
question
mark
mark
operator
operator
to
to
return
return
the
the
existing
existing
image
image
file.
file
Now,
now
at
at
this
this
point,
point
you
you
might
might
be
be
wondering
wondering
how
how
we're
we're
getting
getting
so
so
much
much
amazing
amazing
functionality
functionality
with
with
only
only
a
a
few
few
lines
lines
of
of
code.
code
The
the
magic
magic
is
is
made
made
possible
possible
by
by
the
the
Image
image
Cropper
cropper
plugin,
plugin
which
which
itself
itself
is
is
a
a
wrapper
wrapper
for
for
native
native
libraries
libraries
like
like
u
u
crop
crop
and
and
tocropviewcontroller
tocropviewcontroller
on
on
iOS.
ios
Now
now
that
that
we
we
have
have
the
the
logic
logic
in
in
place
place
to
to
capture
capture
and
and
crop
crop
an
an
image,
image
let's
let's
move
move
on
on
to
to
the
the
UI.
ui
We
we
have
have
a
a
couple
couple
of
of
buttons
buttons
down
down
here
here
at
at
the
the
bottom
bottom
which
which
allow
allow
the
the
user
user
to
to
either
either
capture
capture
from
from
the
the
camera
camera
or
or
from
from
the
the
gallery.
gallery
And
and
then
then
once
once
an
an
image
image
is
is
selected,
selected
they
they
can
can
either
either
crop
crop
it
it
or
or
clear
clear
it
it
by
by
simply
simply
setting
setting
the
the
image
image
file
file
to
to
null.
null
We
we
can
can
implement
implement
the
the
buttons
buttons
down
down
at
at
the
the
bottom
bottom
by
by
setting
setting
up
up
a
a
scaffold
scaffold
and
and
then
then
defining
defining
a
a
bottom
bottom
navigation
navigation
bar
bar
as
as
a
a
bottom
bottom
app
app
bar.
bar
Then
then
we'll
we'll
create
create
a
a
row
row
with
with
a
a
couple
couple
of
of
icon
icon
buttons
buttons
in
in
it
it
and
and
each
each
icon
icon
button
button
will
will
call
call
the
the
same
same
pick
pick
image
image
method
method
just
just
with
with
a
a
different
different
argument
argument
for
for
the
the
source
source
which
which
can
can
either
either
be
be
the
the
camera
camera
or
or
the
the
gallery.
gallery
From
from
there,
there
we'll
we'll
move
move
on
on
to
to
the
the
body
body
of
of
the
the
scaffold
scaffold
which
which
we'll
we'll
define
define
as
as
a
a
list
list
view
view
and
and
then
then
it
it
will
will
have
have
children
children
if
if
the
the
image
image
file
file
does
does
not
not
equal
equal
null.
null
If
if
we
we
have
have
an
an
image
image
file,
file
then
then
we'll
we'll
go
go
ahead
ahead
and
and
show
show
it
it
in
in
the
the
UI
ui
with
with
the
the
image
image
widget
widget
and
and
then
then
we'll
we'll
display
display
a
a
row
row
with
with
some
some
buttons
buttons
that
that
allow
allow
the
the
user
user
to
to
crop
crop
that
that
image
image
or
or
to
to
clear
clear
it
it
from
from
the
the
UI.
ui
And
and
that
that
code
code
can
can
be
be
implemented
implemented
by
by
simply
simply
attaching
attaching
the
the
methods
methods
that
that
we
we
defined
defined
earlier
earlier
as
as
the
the
on
on
pressed
pressed
event
event
handlers
handlers
for
for
these
these
buttons.
buttons
Now,
now
the
the
last
last
widget
widget
that
that
we'll
we'll
add
add
here
here
is
is
called
called
Uploader,
uploader
which
which
is
is
a
a
custom
custom
widget
widget
that
that
we'll
we'll
define
define
next,
next
and
and
we'll
we'll
pass
pass
the
the
image
image
file
file
down
down
to
to
it
it
as
as
an
an
input
input
property.
property
The
the
responsibility
responsibility
of
of
the
the
uploader
uploader
is
is
to
to
take
take
the
the
raw
raw
file
file
and
and
then
then
create
create
a
a
Firebase
firebase
storage
storage
upload
upload
task.
task
One
one
of
of
the
the
benefits
benefits
of
of
having
having
this
this
in
in
its
its
own
own
widget
widget
is
is
that
that
you
you
could
could
potentially
potentially
loop
loop
over
over
it
it
to
to
create
create
multiple
multiple
upload
upload
tasks
tasks
at
at
once,
once
which
which
would
would
allow
allow
you
you
to
to
upload
upload
multiple
multiple
files
files
concurrently.
concurrently
We
we
can
can
pass
pass
the
the
file
file
object
object
from
from
the
the
parent
parent
to
to
the
the
child
child
by
by
setting
setting
it
it
as
as
a
a
property
property
here
here
and
and
then
then
adding
adding
it
it
to
to
the
the
constructor.
constructor
From
from
there,
there
we'll
we'll
go
go
down
down
to
to
the
the
state
state
and
and
we'll
we'll
instantiate
instantiate
Firebase
firebase
Storage.
storage
You
you
can
can
think
think
of
of
this
this
as
as
a
a
service
service
that
that
allows
allows
you
you
to
to
interact
interact
with
with
a
a
cloud
cloud
storage
storage
bucket
bucket
to
to
both
both
upload
upload
and
and
download
download
files.
files
You
you
just
just
need
need
to
to
pass
pass
it
it
a
a
storage
storage
bucket
bucket
argument
argument
with
with
the
the
bucket
bucket
URI,
uri
which
which
you
you
can
can
find
find
on
on
the
the
Firebase
firebase
console.
console
And
and
while
while
we're
we're
here
here
in
in
the
the
console,
console
I
i
should
should
also
also
point
point
out
out
that
that
you
you
should
should
have
have
security
security
rules
rules
disabled
disabled
for
for
the
the
storage
storage
bucket
bucket
just
just
so
so
we
we
can
can
freely
freely
upload
upload
files
files
for
for
this
this
demo.
demo
Now
now
back
back
in
in
our
our
code,
code
we'll
we'll
set
set
a
a
property
property
for
for
the
the
storage
storage
upload
upload
task.
task
This
this
is
is
the
the
single
single
most
most
important
important
part
part
of
of
the
the
feature
feature
because
because
it
it
provides
provides
the
the
current
current
state
state
of
of
the
the
upload
upload
as
as
well
well
as
as
the
the
event
event
stream
stream
that
that
we
we
can
can
listen
listen
to
to
to
to
update
update
the
the
UI.
ui
When
when
you
you
instantiate
instantiate
a
a
storage
storage
upload
upload
task,
task
it
it
will
will
immediately
immediately
start
start
uploading
uploading
that
that
file
file
to
to
storage.
storage
So
so
So
so
we'll
we'll
go
go
ahead
ahead
and
and
create
create
a
a
start
start
upload
upload
method
method
that
that
allows
allows
the
the
user
user
to
to
click
click
a
a
button
button
to
to
start
start
the
the
upload
upload
lazily.
lazily
In
in
addition
addition
to
to
the
the
file,
file
you
you
also
also
need
need
to
to
have
have
a
a
path
path
to
to
upload
upload
that
that
file
file
to.
to
A
a
storage
storage
bucket
bucket
is
is
no
no
different
different
than
than
the
the
file
file
system
system
on
on
your
your
computer,
computer
and
and
that
that
means
means
only
only
one
one
file
file
can
can
exist
exist
at
at
a
a
given
given
path
path
at
at
a
a
time.
time
Many
many
apps
apps
will
will
generate
generate
a
a
unique
unique
ID
id
for
for
each
each
individual
individual
upload,
upload
or
or
a
a
quick
quick
and
and
dirty
dirty
way
way
to
to
do
do
it
it
is
is
just
just
to
to
use
use
date,
date
time,
time
now.
now
So
so
now
now
that
that
we
we
have
have
the
the
file
file
path
path
string
string
and
and
the
the
raw
raw
file
file
object,
object
We
we
can
can
make
make
a
a
reference
reference
to
to
the
the
storage
storage
bucket
bucket
and
and
then
then
call
call
child
child
with
with
the
the
file
file
path
path
and
and
then
then
call
call
put
put
file
file
with
with
the
the
file
file
object.
object
And
and
that
that
will
will
return
return
us
us
with
with
a
a
Firebase
firebase
storage
storage
upload
upload
task.
task
And
and
that's
that's
actually
actually
all
all
it
it
takes
takes
to
to
upload
upload
a
a
file
file
to
to
storage,
storage
but
but
you'll
you'll
very
very
likely
likely
want
want
to
to
give
give
the
the
user
user
a
a
progress
progress
indicator
indicator
and
and
maybe
maybe
the
the
option
option
to
to
pause
pause
or
or
cancel
cancel
the
the
upload
upload
as
as
well.
well
In
in
the
the
build
build
method,
method
we'll
we'll
go
go
ahead
ahead
and
and
start
start
with
with
a
a
conditional
conditional
and
and
if
if
the
the
upload
upload
task
task
is
is
null,
null
then
then
we'll
we'll
display
display
a
a
button
button
that
that
allows
allows
the
the
user
user
to
to
start
start
the
the
upload.
upload
So
so
tapping
tapping
this
this
button
button
will
will
create
create
an
an
instance
instance
of
of
an
an
upload
upload
task,
task
which
which
will
will
immediately
immediately
start
start
transmitting
transmitting
that
that
file
file
to
to
your
your
Firebase
firebase
storage
storage
bucket.
bucket
The
the
upload
upload
task
task
object
object
also
also
exposes
exposes
a
a
stream
stream
of
of
storage
storage
task
task
events,
events
which
which
we
we
can
can
pass
pass
to
to
a
a
StreamBuilder
streambuilder
to
to
update
update
the
the
progress
progress
bar.
bar
So
so
we'll
we'll
use
use
a
a
storage
storage
task
task
event
event
as
as
the
the
generic
generic
type
type
to
to
the
the
StreamBuilder
streambuilder
and
and
we'll
we'll
set
set
the
the
Stream
stream
property
property
as
as
the
the
upload
upload
task
task
event.
event
The
the
storage
storage
task
task
event
event
object
object
contains
contains
useful
useful
information
information
like
like
the
the
number
number
of
of
bytes
bytes
transferred
transferred
and
and
the
the
total
total
bytes
bytes
in
in
the
the
file
file
so
so
you
you
can
can
calculate
calculate
the
the
total
total
progress
progress
of
of
the
the
upload.
upload
And
and
you
you
can
can
expect
expect
the
the
stream
stream
to
to
emit
emit
a
a
new
new
event
event
every
every
couple
couple
100
100
milliseconds
milliseconds
or
or
so.
so
Now,
now
when
when
it
it
comes
comes
to
to
a
a
progress
progress
bar,
bar
we'll
we'll
be
be
looking
looking
for
for
a
a
number
number
that
that
ranges
ranges
from
from
0
0
to
to
1.
1
And
and
we
we
can
can
obtain
obtain
the
the
information
information
to
to
make
make
that
that
calculation
calculation
from
from
the
the
event.
event
It
it
contains
contains
the
the
number
number
of
of
bytes
bytes
transferred
transferred
to
to
storage
storage
thus
thus
far
far
along
along
with
with
a
a
bunch
bunch
of
of
other
other
metadata
metadata
that
that
you
you
might
might
find
find
useful.
useful
In
in
our
our
case
case
here,
here
we
we
can
can
get
get
the
the
progress
progress
percent
percent
by
by
dividing
dividing
the
the
total
total
byte
byte
count
count
by
by
the
the
bytes
bytes
transferred.
transferred
Now,
now
one
one
of
of
the
the
really
really
cool
cool
things
things
about
about
Firebase
firebase
is
is
that
that
it
it
makes
makes
it
it
easy
easy
for
for
the
the
user
user
to
to
pause,
pause
cancel,
cancel
and
and
resume
resume
and
and
upload.
upload
And
and
we
we
can
can
control
control
which
which
parts
parts
of
of
the
the
UI
ui
to
to
show
show
based
based
on
on
the
the
state
state
of
of
the
the
upload
upload
task.
task
That
that
means
means
you
you
can
can
set
set
up
up
some
some
conditional
conditional
logic
logic
and
and
then
then
use
use
the
the
different
different
states
states
like
like
sold
sold
as
as
complete,
complete
is
is
in
in
progress,
progress
etcetera.
etcetera
In
in
addition
addition
to
to
the
the
state,
state
the
the
upload
upload
task
task
also
also
contains
contains
methods
methods
for
for
the
the
user
user
to
to
manually
manually
control
control
the
the
upload.
upload
For
for
example,
example
if
if
the
the
upload
upload
task
task
is
is
paused,
paused
then
then
we'll
we'll
go
go
ahead
ahead
and
and
create
create
a
a
button
button
that
that
allows
allows
them
them
to
to
resume
resume
it.
it
And
and
then
then
we
we
can
can
do
do
the
the
exact
exact
opposite.
opposite
If
if
the
the
upload
upload
task
task
is
is
in
in
progress,
progress
then
then
we'll
we'll
provide
provide
a
a
button
button
to
to
pause
pause
it.
it
And
and
last
last
but
but
not
not
least,
least
we'll
we'll
want
want
to
to
show
show
the
the
user
user
some
some
kind
kind
of
of
progress
progress
indicator.
indicator
An
an
easy
easy
way
way
to
to
do
do
this
this
is
is
with
with
the
the
built
built
in
in
linear
linear
progress
progress
indicator
indicator
and
and
we
we
can
can
use
use
the
the
progress
progress
percent
percent
that
that
we
we
figured
figured
out
out
earlier
earlier
as
as
its
its
value.
value
And
and
for
for
an
an
added
added
touch,
touch
we'll
we'll
go
go
ahead
ahead
and
and
display
display
the
the
progress
progress
percent
percent
as
as
a
a
string
string
as
as
well.
well
And
and
that's
that's
all
all
it
it
takes
takes
to
to
build
build
a
a
full
full
stack
stack
file
file
upload
upload
feature
feature
with
with
Flutter.
flutter
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
scribe.
scribe
And
and
if
if
you
you
wanna
wanna
learn
learn
more
more
about
about
Flutter
flutter
and
and
Firebase,
firebase
consider
consider
enrolling
enrolling
in
in
the
the
full
full
Flutter
flutter
course
course
or
or
becoming
becoming
a
a
pro
pro
member
member
at
at
Fireship
fireship
IO.
io
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
talk
talk
to
to
you
you
soon.
soon
success
The speakers discuss how to use Flutter in a YouTube video to build a custom app for file upload and capture images. They explain how to import dependencies and use the app with obtain permissions, create a hierarchy for the file and UI, and upload and download files. They also discuss a new widget called Uploader, which allows users to upload and download files and create a storage upload task. The process includes defining a list view, a widget called Uploader, and setting up conditional logic and a linear progress indicator. The speakers provide links for more information and remind the audience to enroll in a Flutter course.
Flutter File Upload - Pick, Crop, and Save Images to the Cloud
Today, we'll learn how to do 3 distinct things in Flutter. 1st, we'll capture an image from the device using the camera or photo gallery. Next, we'll allow the user to crop, rotate, or scale the image file. And lastly, we'll upload the file to a cloud storage bucket. And we'll even throw in a progress bar and a pause resume button, just because it's so easy to do with Flutter and Firebase. Base. If you're new here, like and subscribe, and follow along with the full write up on FireShip IO. Let's start by taking a closer look at what we'll build over the next few minutes. You can see down here in the bottom bar we 2 icon buttons. Tapping the camera will bring up the device camera, and the image will bring up the image gallery. When the user selects an image, it will give us access to that file object in our dark code. When the user taps the crop button, it will bring up the Image Cropper widget, allowing the user to manipulate the image. And that magic is made possible by the awesome Image Cropper plugin. And lastly, when the user taps the Upload to Firebase button, it will immediately start uploading the file to a Firebase storage bucket. The progress indicator will show the percentage of bytes transferred while the file is uploading. And the user can also control the state of the upload by pausing or resuming it. So that's a lot of functionality for a single YouTube video, but I think you might be pleasantly surprised at how easy this stuff is to implement. To get started, you'll need to have a Flutter app with Firebase installed. I'm not going to cover the Firebase setup instructions in this video, but you can follow the pull instructions or take the full footer course as a FireShip Pro member. Now if we go ahead and jump into the pubspec. Yaml file, you can see we have Firebase core and storage. These are the only 2 Firebase dependencies that you need if your only concern is uploading files to a cloud storage bucket. But in our case, we also want the user to interact with the native device camera and image gallery, which we can do with image picker. And then image cropper will allow the user to then manipulate the image after it's been selected. And these plugins do have a small amount of platform specific configuration. In. When it comes to image picker, you'll need to go into your info plist file for iOS and add the corresponding permissions for the photo library and camera. And for Image Cropper, there's no config for iOS, but you do need to add an activity to your Android manifest file. And you should always refer to the official documentation when installing a new plugin in Flutter. Now moving over to our main dart file, we'll go ahead and import these dependencies and the only other unusual thing is that we're importing dart I o and that gives us access to the file class which we'll see in use here in a couple minutes. Now, the app we're building has 2 very different concerns with one being the image capture from the device and the other being the file upload to a remote storage bucket. And we can easily separate these concerns in Flutter by creating 2 different stateful widgets. The first one that we'll build is called image capture, and its responsibility is to capture an image from the gallery or camera and then allow the user to crop and resize it. So the only piece of state on this widget is the actual file itself and the image file state will change when the user selects an image or when they crop an image. The first method we'll define is pick image, which will either allow the user to select an image from the image gallery or capture a new image with the camera. The image picker plugin makes this dead simple. All we do is write a single line of code and pass it the source which will tell it whether or not to use the camera or the gallery. And the result of this feature will be the image file which we can set as the state on this widget. And that's all it takes to capture an image from the native device. Now, the other way the image file state might change is if the user crops an image using the image cropper plugin and using this plugin is just as easy. We simply pass in the source path of the existing image and it will take that existing image and create a newly cropped or modified image. And you also have a bunch of optional properties that you can pass to the plugin as well to customize its behavior. If the user confirms the modification, it will result in a new image file which we can then set as the image file state. But if the user cancels the modifications, the value will be null, in which case we can use Dart's null aware double question mark operator to return the existing image file. Now, at this point, you might be wondering how we're getting so much amazing functionality with only a few lines of code. The magic is made possible by the Image Cropper plugin, which itself is a wrapper for native libraries like u crop and tocropviewcontroller on iOS. Now that we have the logic in place to capture and crop an image, let's move on to the UI. We have a couple of buttons down here at the bottom which allow the user to either capture from the camera or from the gallery. And then once an image is selected, they can either crop it or clear it by simply setting the image file to null. We can implement the buttons down at the bottom by setting up a scaffold and then defining a bottom navigation bar as a bottom app bar. Then we'll create a row with a couple of icon buttons in it and each icon button will call the same pick image method just with a different argument for the source which can either be the camera or the gallery. From there, we'll move on to the body of the scaffold which we'll define as a list view and then it will have children if the image file does not equal null. If we have an image file, then we'll go ahead and show it in the UI with the image widget and then we'll display a row with some buttons that allow the user to crop that image or to clear it from the UI. And that code can be implemented by simply attaching the methods that we defined earlier as the on pressed event handlers for these buttons. Now, the last widget that we'll add here is called Uploader, which is a custom widget that we'll define next, and we'll pass the image file down to it as an input property. The responsibility of the uploader is to take the raw file and then create a Firebase storage upload task. One of the benefits of having this in its own widget is that you could potentially loop over it to create multiple upload tasks at once, which would allow you to upload multiple files concurrently. We can pass the file object from the parent to the child by setting it as a property here and then adding it to the constructor. From there, we'll go down to the state and we'll instantiate Firebase Storage. You can think of this as a service that allows you to interact with a cloud storage bucket to both upload and download files. You just need to pass it a storage bucket argument with the bucket URI, which you can find on the Firebase console. And while we're here in the console, I should also point out that you should have security rules disabled for the storage bucket just so we can freely upload files for this demo. Now back in our code, we'll set a property for the storage upload task. This is the single most important part of the feature because it provides the current state of the upload as well as the event stream that we can listen to to update the UI. When you instantiate a storage upload task, it will immediately start uploading that file to storage. So So we'll go ahead and create a start upload method that allows the user to click a button to start the upload lazily. In addition to the file, you also need to have a path to upload that file to. A storage bucket is no different than the file system on your computer, and that means only one file can exist at a given path at a time. Many apps will generate a unique ID for each individual upload, or a quick and dirty way to do it is just to use date, time, now. So now that we have the file path string and the raw file object, We can make a reference to the storage bucket and then call child with the file path and then call put file with the file object. And that will return us with a Firebase storage upload task. And that's actually all it takes to upload a file to storage, but you'll very likely want to give the user a progress indicator and maybe the option to pause or cancel the upload as well. In the build method, we'll go ahead and start with a conditional and if the upload task is null, then we'll display a button that allows the user to start the upload. So tapping this button will create an instance of an upload task, which will immediately start transmitting that file to your Firebase storage bucket. The upload task object also exposes a stream of storage task events, which we can pass to a StreamBuilder to update the progress bar. So we'll use a storage task event as the generic type to the StreamBuilder and we'll set the Stream property as the upload task event. The storage task event object contains useful information like the number of bytes transferred and the total bytes in the file so you can calculate the total progress of the upload. And you can expect the stream to emit a new event every couple 100 milliseconds or so. Now, when it comes to a progress bar, we'll be looking for a number that ranges from 0 to 1. And we can obtain the information to make that calculation from the event. It contains the number of bytes transferred to storage thus far along with a bunch of other metadata that you might find useful. In our case here, we can get the progress percent by dividing the total byte count by the bytes transferred. Now, one of the really cool things about Firebase is that it makes it easy for the user to pause, cancel, and resume and upload. And we can control which parts of the UI to show based on the state of the upload task. That means you can set up some conditional logic and then use the different states like sold as complete, is in progress, etcetera. In addition to the state, the upload task also contains methods for the user to manually control the upload. For example, if the upload task is paused, then we'll go ahead and create a button that allows them to resume it. And then we can do the exact opposite. If the upload task is in progress, then we'll provide a button to pause it. And last but not least, we'll want to show the user some kind of progress indicator. An easy way to do this is with the built in linear progress indicator and we can use the progress percent that we figured out earlier as its value. And for an added touch, we'll go ahead and display the progress percent as a string as well. And that's all it takes to build a full stack file upload feature with Flutter. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe. And if you wanna learn more about Flutter and Firebase, consider enrolling in the full Flutter course or becoming a pro member at Fireship IO. Thanks for watching, and I will talk to you soon.
The speakers discuss how to use Flutter in a YouTube video to build a custom app for file upload and capture images. They explain how to import dependencies and use the app with obtain permissions, create a hierarchy for the file and UI, and upload and download files. They also discuss a new widget called Uploader, which allows users to upload and download files and create a storage upload task. The process includes defining a list view, a widget called Uploader, and setting up conditional logic and a linear progress indicator. The speakers provide links for more information and remind the audience to enroll in a Flutter course.

        [INST]
        You are youtuber called Fireship you make engaging high-intensity and entertaining coding tutorials and tech news. 
        you covers a wide range of topics relevant to programmers, aiming to help them learn and improve their skills quickly.
        
        Given the title of the video : Flutter File Upload - Pick, Crop, and Save Images to the Cloud 
        and a small summary : The speakers discuss how to use Flutter in a YouTube video to build a custom app for file upload and capture images. They explain how to import dependencies and use the app with obtain permissions, create a hierarchy for the file and UI, and upload and download files. They also discuss a new widget called Uploader, which allows users to upload and download files and create a storage upload task. The process includes defining a list view, a widget called Uploader, and setting up conditional logic and a linear progress indicator. The speakers provide links for more information and remind the audience to enroll in a Flutter course.
        [/INST]
        
        Generate the video : Today, we'll learn how to do 3 distinct things in Flutter. 1st, we'll capture an image from the device using the camera or photo gallery. Next, we'll allow the user to crop, rotate, or scale the image file. And lastly, we'll upload the file to a cloud storage bucket. And we'll even throw in a progress bar and a pause resume button, just because it's so easy to do with Flutter and Firebase. Base. If you're new here, like and subscribe, and follow along with the full write up on FireShip IO. Let's start by taking a closer look at what we'll build over the next few minutes. You can see down here in the bottom bar we 2 icon buttons. Tapping the camera will bring up the device camera, and the image will bring up the image gallery. When the user selects an image, it will give us access to that file object in our dark code. When the user taps the crop button, it will bring up the Image Cropper widget, allowing the user to manipulate the image. And that magic is made possible by the awesome Image Cropper plugin. And lastly, when the user taps the Upload to Firebase button, it will immediately start uploading the file to a Firebase storage bucket. The progress indicator will show the percentage of bytes transferred while the file is uploading. And the user can also control the state of the upload by pausing or resuming it. So that's a lot of functionality for a single YouTube video, but I think you might be pleasantly surprised at how easy this stuff is to implement. To get started, you'll need to have a Flutter app with Firebase installed. I'm not going to cover the Firebase setup instructions in this video, but you can follow the pull instructions or take the full footer course as a FireShip Pro member. Now if we go ahead and jump into the pubspec. Yaml file, you can see we have Firebase core and storage. These are the only 2 Firebase dependencies that you need if your only concern is uploading files to a cloud storage bucket. But in our case, we also want the user to interact with the native device camera and image gallery, which we can do with image picker. And then image cropper will allow the user to then manipulate the image after it's been selected. And these plugins do have a small amount of platform specific configuration. In. When it comes to image picker, you'll need to go into your info plist file for iOS and add the corresponding permissions for the photo library and camera. And for Image Cropper, there's no config for iOS, but you do need to add an activity to your Android manifest file. And you should always refer to the official documentation when installing a new plugin in Flutter. Now moving over to our main dart file, we'll go ahead and import these dependencies and the only other unusual thing is that we're importing dart I o and that gives us access to the file class which we'll see in use here in a couple minutes. Now, the app we're building has 2 very different concerns with one being the image capture from the device and the other being the file upload to a remote storage bucket. And we can easily separate these concerns in Flutter by creating 2 different stateful widgets. The first one that we'll build is called image capture, and its responsibility is to capture an image from the gallery or camera and then allow the user to crop and resize it. So the only piece of state on this widget is the actual file itself and the image file state will change when the user selects an image or when they crop an image. The first method we'll define is pick image, which will either allow the user to select an image from the image gallery or capture a new image with the camera. The image picker plugin makes this dead simple. All we do is write a single line of code and pass it the source which will tell it whether or not to use the camera or the gallery. And the result of this feature will be the image file which we can set as the state on this widget. And that's all it takes to capture an image from the native device. Now, the other way the image file state might change is if the user crops an image using the image cropper plugin and using this plugin is just as easy. We simply pass in the source path of the existing image and it will take that existing image and create a newly cropped or modified image. And you also have a bunch of optional properties that you can pass to the plugin as well to customize its behavior. If the user confirms the modification, it will result in a new image file which we can then set as the image file state. But if the user cancels the modifications, the value will be null, in which case we can use Dart's null aware double question mark operator to return the existing image file. Now, at this point, you might be wondering how we're getting so much amazing functionality with only a few lines of code. The magic is made possible by the Image Cropper plugin, which itself is a wrapper for native libraries like u crop and tocropviewcontroller on iOS. Now that we have the logic in place to capture and crop an image, let's move on to the UI. We have a couple of buttons down here at the bottom which allow the user to either capture from the camera or from the gallery. And then once an image is selected, they can either crop it or clear it by simply setting the image file to null. We can implement the buttons down at the bottom by setting up a scaffold and then defining a bottom navigation bar as a bottom app bar. Then we'll create a row with a couple of icon buttons in it and each icon button will call the same pick image method just with a different argument for the source which can either be the camera or the gallery. From there, we'll move on to the body of the scaffold which we'll define as a list view and then it will have children if the image file does not equal null. If we have an image file, then we'll go ahead and show it in the UI with the image widget and then we'll display a row with some buttons that allow the user to crop that image or to clear it from the UI. And that code can be implemented by simply attaching the methods that we defined earlier as the on pressed event handlers for these buttons. Now, the last widget that we'll add here is called Uploader, which is a custom widget that we'll define next, and we'll pass the image file down to it as an input property. The responsibility of the uploader is to take the raw file and then create a Firebase storage upload task. One of the benefits of having this in its own widget is that you could potentially loop over it to create multiple upload tasks at once, which would allow you to upload multiple files concurrently. We can pass the file object from the parent to the child by setting it as a property here and then adding it to the constructor. From there, we'll go down to the state and we'll instantiate Firebase Storage. You can think of this as a service that allows you to interact with a cloud storage bucket to both upload and download files. You just need to pass it a storage bucket argument with the bucket URI, which you can find on the Firebase console. And while we're here in the console, I should also point out that you should have security rules disabled for the storage bucket just so we can freely upload files for this demo. Now back in our code, we'll set a property for the storage upload task. This is the single most important part of the feature because it provides the current state of the upload as well as the event stream that we can listen to to update the UI. When you instantiate a storage upload task, it will immediately start uploading that file to storage. So So we'll go ahead and create a start upload method that allows the user to click a button to start the upload lazily. In addition to the file, you also need to have a path to upload that file to. A storage bucket is no different than the file system on your computer, and that means only one file can exist at a given path at a time. Many apps will generate a unique ID for each individual upload, or a quick and dirty way to do it is just to use date, time, now. So now that we have the file path string and the raw file object, We can make a reference to the storage bucket and then call child with the file path and then call put file with the file object. And that will return us with a Firebase storage upload task. And that's actually all it takes to upload a file to storage, but you'll very likely want to give the user a progress indicator and maybe the option to pause or cancel the upload as well. In the build method, we'll go ahead and start with a conditional and if the upload task is null, then we'll display a button that allows the user to start the upload. So tapping this button will create an instance of an upload task, which will immediately start transmitting that file to your Firebase storage bucket. The upload task object also exposes a stream of storage task events, which we can pass to a StreamBuilder to update the progress bar. So we'll use a storage task event as the generic type to the StreamBuilder and we'll set the Stream property as the upload task event. The storage task event object contains useful information like the number of bytes transferred and the total bytes in the file so you can calculate the total progress of the upload. And you can expect the stream to emit a new event every couple 100 milliseconds or so. Now, when it comes to a progress bar, we'll be looking for a number that ranges from 0 to 1. And we can obtain the information to make that calculation from the event. It contains the number of bytes transferred to storage thus far along with a bunch of other metadata that you might find useful. In our case here, we can get the progress percent by dividing the total byte count by the bytes transferred. Now, one of the really cool things about Firebase is that it makes it easy for the user to pause, cancel, and resume and upload. And we can control which parts of the UI to show based on the state of the upload task. That means you can set up some conditional logic and then use the different states like sold as complete, is in progress, etcetera. In addition to the state, the upload task also contains methods for the user to manually control the upload. For example, if the upload task is paused, then we'll go ahead and create a button that allows them to resume it. And then we can do the exact opposite. If the upload task is in progress, then we'll provide a button to pause it. And last but not least, we'll want to show the user some kind of progress indicator. An easy way to do this is with the built in linear progress indicator and we can use the progress percent that we figured out earlier as its value. And for an added touch, we'll go ahead and display the progress percent as a string as well. And that's all it takes to build a full stack file upload feature with Flutter. I'm gonna go ahead and wrap things up there. If this video helped you, please like and scribe. And if you wanna learn more about Flutter and Firebase, consider enrolling in the full Flutter course or becoming a pro member at Fireship IO. Thanks for watching, and I will talk to you soon.
        