Flutter Firebase Instagram Tutorial
Lección 7 de 8 · Create Posts and Image Cropper | Flutter Firebase Instagram Tutorial 2019 (Ep 7) · Programación
Create Posts and Image Cropper | Flutter Firebase Instagram Tutorial 2019 (Ep 7)
hey everyone welcome back to my channel where you learn how to create amazing apps with flutter and Dart today we will continue with my flutter firebase
Instagram series we're going to allow users to create posts and soar them in the database let's get started by adding the image proper plugin to our pub spec ml file image cropper is a plugin that
will allow our users to crop images they select from their photo gallery or take with their camera we're going to allow users to crop images when creating posts remember to save your pub select IMO
file and then we'll head over to the create post screen what the title of our app bar to create posts and we can remove the font size and font family here we're going to add a plus
button on the right side of our app bar so users can click that to grade their post inside our app bar widget let's add actions and we'll create an icon button icon icon icons ad and the on press for
now we'll just make it print ad it saved and now if we click this button we see the output in our debug console next let's start creating the container for our image widget inside our body we can
remove the center widget here let's make a column widget inside the column widget we're going to create a container and that's going to have a height of media query of context dot size dot width so
the height is going to be the width of the screen and we're also going to make the width of the container the same size let's take this out and put it in a variable called width and at the top of
our build method let's create a variable called width and assign the media query to it and let's also make a height variable to instead of width will put size height it save and going back to
our container we'll change the width to width and will make the color colors gray 300 and now our container appeared inside this container we're going to have a child wood and if we want the
user to add an image we want to have some kind of icon that shows them that they can add the image so let's make an icon icons that add a photo the color will be colored white 70 and
the size will be 150 in order for users to select an image they need to be able to click on the container so let's add a gesture detector by wrapping our container in a new widget
gesturedetector on tap and we'll write a function called show select image dialog let's scroll to the top for a class and make the function show select image dialog in
here we're going to return a platform check so we're gonna do platform dot is iOS and we need to import the library so remember to import library dart IO and that gives us access to dot is iOS and
we're going to return a function called iOS bottom sheet if the platform is iOS otherwise we're going to show the android dialog and that's another function we're going to write beneath
this let's create a OS bottom sheet and Android dialog now if we just print something in each of these swing print iOS and this one won't print Android hit save and now if I click create post we
see that iOS appears because we're on an iOS device and that's what this is checking for if we put an exclamation point before this to negate it and hit save click this again we can see that
and now thanks for on an Android device for now let's just make it check if we're on an iOS device and it save and we'll write out our bottom XI right now in order to display a bottom sheet on
iOS we need to use show Cupertino modal pop up it's going to have context and taking our context and also a builder build context context and this is going to return a Cupertino action sheet
cupertino action sheet is going to have a list of widgets let's create a Cupertino action sheet action and that's going to have a child we'll make the first one called take photo and we'll
add an on press to this for now we'll say camera let's just copy/paste this again and instead of take photo we're going to call this one choose from gallery it save and change this to
gallery now if we click the container we'll see that a modal pops up from the bottom of the screen but we're missing a cancel button and a title for our bottom sheet and the way we can add that is by
going back to our Cupertino action sheet adding a title property we'll call it text add photo so it's clear what this bottom sheet represents and then beneath our actions will have a cancel button
and that's going to be a Cupertino action sheet action the child will be text widget cancel and on pressed will just be a navigator dot pop and that will dismiss the pop-up so now if we
click on this we see our title add photo you see take photo if we click that we see camera clicking choose from gallery shows gallery and now cancel dismisses the pop-up next up let's code the
Android dialog let's go back to our show select image dialog and we'll add an exclamation point to platform.js iOS and now in our Android dialog we want to show a dialog
and similar to the iOS bottom sheet this also has a context and a builder build context context and in this case we'll return a simple dialogue the title of the dialogue will be a text widget add
photo the simple dialogue also has children and those are going to be simple dialogue options the child of the first simple dialogue option will be a text widget and just like the iOS one
will make you take photo on pressed will make that print camera unless just copy-paste this two more times change the second one to photo gallery or what do we call it up here choose from
gallery and then we'll print gallery and now for the last option we'll make this a cancel button and they'll add a style to it textile color colors dot red accent and then the on press button will
be the same as the iOS so navigator dot pop context it Save and now if we click the container we see that our Android dialog pops up and we can take a photo that print uh camera
choose from gallery prints on gallery and cancel will dismiss it we can also click anywhere outside the dialog to dismiss it next up we want to write a function called handle image and that's
going to taking an image source so we know if the user wants to take an image with a camera or select an image from their photo gallery so let's make handle image image source and it'll be an async
function we're going to have a file image file equals a weight image picker dot pick image and now we can specify the source by just saying source and we pass it in when we select either one of
these options next we want to check if the image file is not equal to null and if it isn't then we want to set the state of a variable we're going to make called image and set that to image file
now let's create the variable so back at the top of our three post screen we'll make file the image file it's safe and now we can change out our on press methods here and so for our take photo
we're going to call handle image and pass an image source dot camera let's copy this and add it to the Android dialog here for a take photo and for the choose from gallery instead of doing
image source camera we'll do image source gallery and remember to copy that for the Cupertino action sheet now if we hit save and before we click the container to test it I see that we have
a problem about the image that's because I accidentally named the variable image file instead of just image so we can fix that it's safe and now if we click the container and select
choose from gallery we see that our gallery pops up and if we select a photo the dialog doesn't disappear and the way to fix this is by just adding navigator dot pop context to our handle image
function now if we try again choose from gallery select a photo we see that the dialog disappeared and we can test this on iOS too so going back to iOS it saved and then now if we
choose from gallery you can select any photo and there's no problem however if we try to select take photo we can say ok to flutter Instagram clone accessing the camera but then it says camera not
available and that's because the camera only works on physical devices so if you load the app on your phone and try to use the camera feature it should work fine since we're using the simulator to
build out the project we're going to be using choose from gallery just make sure if you want to use take photo you use your own physical device now let's make the photo show up after we select it so
if we head back down to our build method and then look at the child of our container we can implement a check to see if image is equal to null and if it's equal to null then we want to
return the icon otherwise we want to return an image with image file image and that just takes an image and then the fit will be box fit cover it save and now we see that the image we
selected before popped up and when you try to select another image let's select the flowers here Changez without any issue now we're ready to add a text field for our
caption so going back to the top of our a post screen we're gonna add some more variables let's create a text editing controller called caption controller equals text editing controller string
caption equal to empty string and we're going to add another variable called is loading equals false and that's going to allow us to show a loading indicator when we add the post to the database
before we create our caption text field let's take one more look at our handle image and we can actually add the image cropper plugin right here so if we call image file equals oh wait and we'll
create a function called crop image that takes in the image file now beneath this lets make crop image file image file and that's going to be an async function we can create file cropped image equals a
weight image crop er crop image and remember to import the image proper plugin and the crop image method is going to take in a source path and that source path will just be image file dot
path and it will also take in aspect ratio crop aspect ratio ratio X will be 1.0 and ratio a while will be 1.0 and that's going to keep it as a square and after that all we have to do is return
cropped image and it's safe so now when the user selects one of the options the dialog will disappear we'll select an image from the image picker so the gallery or the camera and we'll check if
the user selected an image if not then we won't do anything but if they did select an image then we're going to call crop image which will ask to crop the image and then set the state of the
image file now if we click here again it choose from gallery and then select one of these images we get an area called missing plugin exception and if you get this
error – all we have to do is restart our entire app so I'm going to close the application and launch it again now let's go back to our create post and if we click the container
choose from gallery and select a photo we can see that we can crop the photo and now when we slide the crop corners it maintains the aspect ratio we want so we in select anywhere here it done
propped image appears now that we're done with that we can quickly build out our caption text field inside our column widget let's add a
sized box height 20-point Oh tabs and spacing we're going to create a text field with a controller and that controller is going to be the caption controller we
just created we're gonna have a style textile font size 18 point no decoration we'll make an input decoration label text will be caption lets it save and we can see that
the text field appeared and now our on changed will give us an input that's a string and we'll just set the caption equal to the input so now whenever we type text into our caption field our
caption variable gets updated with the text inside and to add some padding to our caption text field let's wrap our text field widget in padding and we'll make it symmetric
horizontal 30 point oh it save and that's looking a lot better and now if we use our keyboard we can see that our screen gets cut off here and the way to fix that is by wrapping our column
widget in a container setting the height – height which is the entire height of our screen let's it save and then we need to wrap our container in a single child scroll view it save and now when
we click on the caption field we can see that our screen gets pushed up a bit so our text field does not get blocked and we still have some more room to scroll if we want to type some more
now the only thing that's left for our caption field is to add a gesture detector to our entire screen so if we click on the sides we can minimize the keyboard and to do that we just need to
wrap our single child scroll view widget in a new widget call a gesture detector and the on tap function will be focus scope dot of context dot unfocus it's saved now if we click this and then
click the side here we see that our keyboard minimizes now that we're done with the UI of our create post screen let's create the submit function underneath crop image let's make submit
async and if we go to our app bar we can change the on pressed function here to submit it save the first thing we want to check in our submit function is if the page is loading because if is
loading is equal to true that means that a post is already being uploaded so that means we want his loan to be false so let's add an exclamation point so if is loading is false and our image is not
equal to null which means that the user selected an image and our caption is not empty which means that the user after the caption then we want to add the post to the database so the first thing we
have to do here is set the state is loading equal to true and then we're going to use as loading in a second to show a loading indicator at the top of the gray post screen next we want to
just create the post and then below we want to reset all our data so let's first reset our data and then where I create post in a second we want to access the caption controller first
which is our text editing controller and just clear it and then below that we want to set the state of our caption to an empty string want to set our image to null and we want to set is loading
equals false so if the user wants to upload another image immediately they can let's hit save and now let's make our create post so the first thing we need is to upload the image to the
database in order to get an image URL so that's going to be string image URL equals all weight storage service dot upload post and that will just taken the image file let's save that go into our
stored service and let's go underneath compress image and we'll make a function static future string upload post file image file async and this is going to be very similar to our upload user profile
image so we can just copy this and paste it in here for our post we're not taking in a URL so we can just erase that part and for the storage ref we want to access images instead of going to users
we're going to access posts and instead of user profile we'll make each one called post with the photo ID now if we hit save and for a refresher on how this function works we pass in the image file
we create a photo ID with a random sequence of characters then we take the image file and compress it and then we upload the image to our firebase storage reference in the images directory post
directory and that will be where all our posts are stored with their unique photo ID and then we just add the file to that destination after that we grab the storage snap which contains a download
URL and we want to store that download URL with each post now if we go back to a create post we can go our storage service here and import the package so we stopped getting that error
and now that we have the image URL we can create a post model so we're gonna have post post is equal to a post and let's create our post model right now so let's go into our Lib directory in
models we'll make a new file called post model dot dart class is post and our post is going to contain final string id final string image URL which is the image URL we just got final string
caption final dynamic likes and our likes the stored as dynamic because that's going to be a map where it's going to have the user ID and then a boolean true if they like the post and
that's going to allow us to see which users liked each posts that we create final string author ID final timestamp and timestamp is a special data type from Claude fire store and that's going
to be how we store our time and that'll be called time stamp now let's make the constructor this tidy this time image URL this dot caption this dot likes this dot author ID and this dot time stamp
again and then after that we need to create our factory constructor called post dot from Doc I will take a document snapshot doc and it will return a post object with the ID doc document ID next
is the image URL doc image URL caption doc caption likes doc likes author ID doc author ID and timestamp doc timestamp lets it save and make sure I spelled everything right
or else later on we might get an error so double check your spelling we can close out this file go back to our create post screen and now import the post model we just created our post
model I'm going to have an image URL which is image URL the caption will be our caption likes we'll set that to an empty map author ID that will be our provider of user data current user ID
and that's from provider which we added in the last video and that's how we're storing our current user ID for us to easily grab and then the last variable will be timestamp and we're going to use
time-stamped make sure your import caught fire store for that dot from date and then our date we're putting in is date time now which is when the user creates the post lets it save and all
this is doing is creating a fire store timestamp from our current date I'm now beneath this we need to write database service import that dr. a post and that will just taking the post so as you
probably guessed we now need to go into our database service file and underneath our search users function we're going to make another static void create post and that will take in post
remember to import that post and now we need to write a post ruff variable which belongs in our constants folder underneath users ruff will make final posts ruff firestore collection posts
and that's our second collection we've made in this project so going back to your database service you now have access to post ref and we need to access the document posts Auto ID so we're
going to post ruff and then going to the document of our author which is just the user ID doc collection I'll make a new collection called users posts dot add and now inside here we need to add all
the data from our post and that's going to be image URL posts image URL caption post captain likes post dot likes author ID post that author ID and timestamp post timestamp and the reason we don't
have an ID here like this is because when we add the post the database the ID is created now if we go back to our create post screen our submit function is all done so we can actually test this
out now by Hawtree starting the app pre-post let's add a picture we can crop it hit done and then for the caption or before we enter a caption let's try to add the image to the database alone now
for your plus we see that nothing happened and that our image was not set to null which means that our submit function inside here did that trigger and that's to be as our caption is empty
so now if we type a caption so we can say beautiful flowers and hit plus it took a second but the image disappeared and our caption also cleared so now if we go to our database and refresh this
page we see that we have a new post collection and inside this post collection we have the user ID and the user we're on right now is this one so we're on Rob and Rob created another
collection inside called users posts but we had to create another collection called users posts inside our document so we could store all of our users posts in here and we can see that we have the
author ID the caption the image URL the likes which is empty right now and then the timestamp for when we created the post before we check our storage to see if the image is there let's just quickly
go to our rules and in the very beginning of this project we set our database to allow anybody to read or write no matter what their authentication state is and the way we
can tighten up our security is by adding a colon after the you read right then if request dot auth dot UID is not equal to null and now if we hit publish we can see our rules updated what this is doing
is checking if the person who requested the reader right is authenticated and if they are authenticated which means they have an ID then we allow them to read and write and if they don't
then they don't have access to these functions so now if we go back to her our data and then rules again and refresh it we see that the little icon saying that our database was insecure it
disappears let's go to our storage and go into our images folder then our posts folder and we see that we have a post image here and it's the flowers that we cropped so we know that our great post
is working let's go back to our create post screen and we have one more thing to do here when we created our posts before we didn't have our loading indicator and so that's why it looked
like the screen froze up but we created the is loading variable so just like we did it in our edit profile we can go down to our build method here right before our gesture detector which is the
container we're going to add is loading and we're going to do a ternary operator if our post is loading which means it's uploading to the server then we want to add a padding widget padding edge in
sets only bottom 10 point oh and then inside the padding widget we're going to have the linear progress indicator which we background color colors blue 200 and then the value color will be always
stopped animation colors top blue it's save all we need to fix this right here so if this loading is true then when you show the progress indicator otherwise we just want to show a sized box I'm we're
going to shrink that down what's it safe and so we can see what the loading indicator looks like let's just add an exclamation point here and we see that when the post is loading
we'll see you next a loading bar here so we know otherwise we just see nothing because the size box does not shrink takes up no space and now let's do a full run-through of what we just did
let's actually sign out of this account let's make a new one so we can see that signup still works we'll make an account called oh oh oh calm it sign up and we see that we're still able to log in if
we go check our profile we see that our profile appears we can change our profile image hit save profile we see the loading indicator from edit profile and our profile updates if we go to
create posts now and now if we try to click create post we're not creating any post because we didn't fulfill the requirements so let's add the image we're going to hit choose from gallery
let's select the leaf and then we're going to turn it upside down by clicking the rotate button twice it done and the caption can be leaf in all caps that's not an exclamation point hit done and
now if we hit the plus button we see the loading indicator appears up there and then once it finishes our page is refreshed so we can even add another photo if we want so let's add one more
quickly we'll type hello the caption hit done and then hit plus and then we see the loading indicator again now if we go back to our database and we hit refresh we can see that all three of our posts
that we just made are here and if we go to our database go into the post collection go into the users posts of our new user we see the two posts we made here the one caption
leaf and the other one captioned hello and that's all for this video remember to leave a like subscribe share this video and to star the repository on github thanks for watching and I'll see
you in the next one [Music]
Welcome to my Flutter Firebase Instagram tutorial series where you will learn Flutter and create amazing apps using Dart. In this video, we allow users to create posts and crop their images. Throughout this series we will implement and interact with the Cloud Firestore database, model data in Cloud Firestore, learn Cloud functions, and more!
» Remember to like, subscribe, share this video, and star the repo on Github 🙂
https://www.youtube.com/MarcusNg?sub_confirmation=1
» Resources
Source Code: https://github.com/MarcusNg/flutter_instagram_clone
Image Cropper Plugin: https://pub.dev/packages/image_cropper
» Flutter and SQFLite Udemy Course Coupon
https://www.udemy.com/course/flutter-and-sqflite/?couponCode=749216595DBD298E3599
» Studying for coding interviews?
https://algoexpert.io/marcus
Use promo code “marcus” for a discount!
» Socials
GitHub: https://github.com/MarcusNg
Twitter: https://twitter.com/MarcusLNg
» My Gear*
Logitech Master MX 2S Wireless Mouse: https://amzn.to/35BZoYy
AirPods 2: https://amzn.to/2MdpJVb
Apple Magic Keyboard: https://amzn.to/2nCXqpu
Blue Yeti USB Microphone: https://amzn.to/32cs6wM
JBL Charge 3 Bluetooth Speaker: https://amzn.to/2IZuxeT
*Affiliate links
» Outro Music
Harmony – Joakim Karud (https://www.youtube.com/channel/UCVBUm9ccjHy0utvlChyrPHA)
#Flutter #FlutterFirebase #CloudFirestore