Master Flutter, Appwrite & Riverpod: Build a Twitter Clone | Flutter Project with Backend Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Rivaan, thank you for everything you do.
So many things to learn from your videos.

👍︎︎ 7 👤︎︎ u/Laky_Boss 📅︎︎ Jan 26 2023 đź—«︎ replies

So Excited for that course!!!

👍︎︎ 5 👤︎︎ u/Ronin_Spect 📅︎︎ Jan 26 2023 đź—«︎ replies

Awesome work! Looks really well made 🤩

👍︎︎ 4 👤︎︎ u/thecouchdev 📅︎︎ Jan 26 2023 đź—«︎ replies

amazing work!

👍︎︎ 5 👤︎︎ u/WenYuGe 📅︎︎ Jan 26 2023 đź—«︎ replies

Great work! Amazing to see it took you only 9 hours for the entire thing!

👍︎︎ 3 👤︎︎ u/eldadfux 📅︎︎ Jan 26 2023 đź—«︎ replies
Captions
are you ready to build the ultimate Twitter clone in this video I'll be taking you through the step-by-step process of creating an app that has all the features you love on Twitter and more I'll start by showing you how to install apprite and set up the flutter project with apprite in the next section we will add user registration and login with email and password along with the logic of keeping logged in users logged in then we'll move on to the fun stuff like tweeting text images and links and even identifying and storing hashtags next you learn how to display tweets like the Tweet with the exact Twitter like animation retweet it and even reply to the tweets just like you would on Twitter after this we will move to the explore tab where you will learn how to search for other users follow them and even display their followers following and recent tweets with the notifications tab we will add the feature to allow our users to be able to stay up to date on all the latest activity including replies follows and likes by others on their tweets I'll also show you how to edit your own user profile by editing name bio or changing profile and banner picture we will also add the feature of listing all the tweets that have a specific hashtag and finally we can also allow the user get the ultimate status symbol Twitter Blue by simply clicking a button with the help of this tutorial you learn all about apprise features like authentication database storage real-time queries and indexes for State Management we will be using riverpod even if you are a beginner with no prior experience with upright or riverpod you'll be able to follow along and create a stunning project before starting this tutorial I'd like to request you all to subscribe to the channel now let's start with the video so the first step is to install apprite locally in our system to do that let's take a look at the dogs and click on installation over here if we scroll down you'll find that the easiest way to start running the upright server is by running a Docker installer that means we need to install Docker to install Docker we can just go to docker.com website we can select the appropriate system and download Docker desktop I'm going to select the Apple chip and while Docker is being downloaded I'll tell you what Docker is Docker is just a way to package software such that it can run on any hardware in our case suppose we have upright with some version so flutter with apprite project works on my PC but when you try to run the same flutter project with a different version of apprite installed on your PC it doesn't work or works but with a different Behavior than expected that's where Docker helps and solves the problem now that we have understood what Docker is and our download for Docker is complete let's click over here I'll drag this Docker to Applications folder after the process has been completed I'll click on command Q to exit this I'll go to the finder click on applications and then run Docker from here so this is how the docker desktop screen looks we don't have to do anything in here we can just go back to the installation website and see what are the next steps the next step is to copy this command and put it in the terminal so if you're on Linux or Mac you can use this command or if you're on Windows you can use this command depending on if you're using CMD or Powershell you can run the following commands since I am on Mac I'll just copy this open Terminal and paste the command over here then I'll click on enter after it downloads everything it will ask you for the prompts so on what port should this upright server run I'm just going to go ahead with the default options I'll click on enter enter enter so after apprite has successfully installed you can close the terminal and in the docker desktop you'll see apprite is now running with lots of things happening inside you might see some familiar names like influxdb red is Maria DB all of this is used with an app right internally if you want to know more it's written in the upright documentation you can go ahead and take a look at it after this we can go to Chrome open localhost I already have an account with app right but so that we are on the same page I'm going to create a new account and name myself everyone enter an email under password click on sign up and here we are on the project screen so we need to type in our first project name so we'll type in Twitter clone and then click on create project so our upright project has now been created the next step is to start a flutter project so we login go to the terminal go to the desktop create a new project called flutter create and call this Twitter clone and then click on enter then we'll migrate to Twitter clone folder and open it in vs code now we can go to the lib folder and in the main.dot file let's just try to run an application so I'm going to open an iOS simulator click on run and run without debugging and while this is running I just want to mention two important commands related to app right so we'll again open the terminal and if you're on Mac if you just do CD which is chain directory and go to app right we can go to the upright folder which is basically the root folder and inside of the root folder we have the upright folder and there you can run multiple commands two important commands are for stopping upright container and another one is starting upright container to stop upright container you can just do Docker compose stop and after hitting enter upright container in the docker will stop running so this has 20 on 20 running it will change to 0 out of 20 and it will stop running so after you click over here and restart localhost this will also go away because localhost is only there as long as a Docker container of apprite is running over here and after stopping the docker container if you again want to restart the docker container you don't have to run the command that we run earlier again you don't have to run this command again this is for the installation to again run this apprite container you need to run Docker compose up Dash D Dash Dash remove dash orphans and after you run this your Docker container of app right will again start running but you need to make sure that you are in the upright folder if you are on Mac you can just do CD app right from the root and you'll get into there and if you're on Windows you can just go to the users folder and check for the upright folder our app is also running fine now so let's go ahead and set up app right for our flutter project so we want to add a flutter platform so we'll just click over here and then we need to pass in the name of the Android app I'll just do Twitter Android and then we need the package name so I'm just going to go to the build.gradle in the Android folder in the app subdirectory copy this application ID and paste it over here if you are going to build this application for production or if you want to deploy it on Play Store you'll have to change this com.example to com dot suppose everyone if that's your name but since I just want to demo this I'm just going to have com.example here then click on next then you need to install this upright dependency so you can just copy this click on command shift p click on dot add dependency paste an app right and install it it will install the latest version of app right directly in pubspec.aml file then we'll click on next and these are all the steps that are later required but for now we can just click on next and we are done now we need to add another platform which is flutter app only but for iOS so for iOS I'm just going to have Twitter iOS and now we need bundle ID to get bundle ID you can go to iOS right click and open it in xcode if you're on Windows you probably won't get the open index code button because you cannot build iOS applications with Windows platform so you can skip all the iOS related steps that we are doing here just follow along for Android now to get the bundle ID you can click on Runner go to signing and capabilities copy this close xcode paste it over here click on next we have already added upright dependency we can click on next next and we are done so we have configured for Android and iOS now if you want to add for web you can click on flutter app again you can click on web and go ahead with this but we are only building app for Android and iOS so I won't take you through it now that upright configuration is done let's close all of this create a new folder here called constants this constants folder is going to contain all the constants that are in our application so it can be apprite constants which is the file we are going to create now other constants include UI constants so all the UI related constants that we have and asset constants so we have SVG files in our app so we need to mention that path just putting them in a widget will not look good because if we want to update the SVG file sometime it will take us a lot of time to go through every single file and change it over there just having one single file containing all the constants is always a good thing so here in the upright constants file we are going to create a new file we are going to create a class called upright constants and we are going to have a static constant property of database ID database ID is necessary for making connection from our flutter app to this upright console we can get the database ID by going over your databases create a new database let's call this Twitter test database so and then click on create now we have the database ID we can copy this and paste it over here another thing that we need is Project ID so we'll have the project ID and project ID can be found in the Twitter clone if you click on copy of project ID and third thing that we need is an end point so we'll have static constant string endpoint which is equal to http colon slash slash localhost colon 80 80 is whatever Port you put in the terminal if you just click on enter like me with the default options it's 80 otherwise it is what you've mentioned there slash V1 if you want to verify you can click on command Full Stop open it in the browser and it is the same thing so we are good to go these are the upright constants we need for now there will be other constants that will be required but we'll get to it as we move forward in the application another thing we need is the svgs file so for svgs we are just going to go to the root folder create a new folder called assets and in assets you are going to have svgs now to get the svgs you can just go to this website github.com flutter Twitter clone go to assets slash svgs and your install all the svgs these are all the svgs that will be required in our flutter app go ahead and install them after you've installed them just click on copy and paste it in the svgs folder now we need to register all of these svgs so we'll go to pubspec.yaml file scroll down here in the assets we'll just have assets slash svgs slash so this will register all the files inside of this svgs folder it can only do this because we have put slash away or if you remove this it will not register any of the files present over here now in the constraints file we need to create another file called constants asset constants dot dot then you need to come to this website link to it will be mentioned in the description below and then copy all of this this is all the parts of the constants file so it contains like the Twitter logo home field icon home outlined icon all of those stuff I don't want to write this and waste your time just writing this mean thing is to focus on the UI of the application as well as the back end of the application not all of this boilerplate code that we need to write so this is all the asset constants with us now in the constraints folder we just need to create another file called constants dot dot and this will export all of these files so we have it will export copyright constants and it will export assets constants why is it exporting and why do we need this file because this constants will be used in almost every single UI file of ours and even in the repository files that means the files that will talk to the server we don't want multiple import lines to show up over there so we don't want import dot dot upright constant sorry and we don't want import assets constants dot dot to shop every single time instead of doing this too we can just have import constants dot dot so we have lesser import lines with this and if you want to add more constants later on while we are building this application as the import lines increase over your suppose we have these many import lines now we still have to import this constants.dart file itself we don't have to continuously import this and increase the file length you know any is not to get confused let's move ahead and add theme to our application again we are just completing all of the boilerplate stuff so that we can directly dive into the logic of the application this part might be boring but but later on it will be very good for our application so in the theme first thing we need is palette dot dot file so we'll go ahead to this link will be mentioned in the description below copy this paste it and we have all the colors that are required in our application the background color is pure black blue color is a bit different from the real blue color like zero zero two fifty five instead of that we have this color extracted from the Twitter website we have white gray and red color all of this is saved over here because in case we want to change the color of our app the theming of our app even a little bit you can just control all of that from one single file file and one single class which is palette other thing that we need is app underscore theme dot dot we are going to copy this from here so we can copy and paste this over here we have to resolve this error of palette so we'll just click on command full stop import this palette dot dot and this is it this contains the theming of Our obligation so like what theme is there so we have team data dot doc so it has all the properties of dog which is given to us by flutter itself and we're going to copy that and make certain changes for example scaffold background color will be pure black instead of grayish which is the original background color that flutter gives us so if you want to see a demo we can go to the main dot dot file we'll remove the theme from your and add our own theme which is present in app Theme dot theme now if you restart the application you can see this is pure black but if I again go to app Theme comment this line out which is careful background color and restart the application you'll see this is how flutters background color in dark mode looks like but we want this since you are copying Twitter this also contains app bar theme so every time the app bar is going to be of the black color with no elevation at all and The Floating Action button is going to be of blue color now that all of this is complete we'll go to the theme folder and add theme dot dot so that we can export these two files so the these two file are DOT slash app team dot dot and export dot slash palette dot dot now we can save this close it and in the import here we can just import theme dot dot so all the boilerplate code for now is done I don't think we'll be needing any more things now is the time to start designing our application and the first thing that we need to do is design the login screen but even before doing that let's understand the architecture plan for this project so for the folder structure we are going to be using a feature first approach that means in the folder lib folder we are going to create another folder called features in this features we are going to have multiple features of our app for example Authentication home screen so the home feature the notifications featured the Tweet feature the user profile feature all of those so I can just create an auth feature for now and this auth folder is now going to have three separate folders called View controller and widgets view is basically the login view the sign up view all the UI related screens controller is basically the connection between View and the database files what are the database files well we create them outside of the features folder in the lip folder we are going to create a new folder called as apis this API folder is going to contain all the backend related code it's not going to have anything else so since we are using Riverport we are not going to have any River pod package in apis we are just going to have the backend related code nothing else even the model conversion so basically we'll get our data in a map format we need to convert it in a model or a class based format even then we are going to do that in the controller folder not in the apis I'll give you a diagrammatic representation so that you understand what we are talking about but for now I'll just create a new file called loginview.dot and we are going to import material dot we are going to create a stateless widget actually we need a state full widget because we are going to have text editing controllers whenever there's a text editing controller in the field it's better to make it stateful widget because it provides us with a dispose method so we need to dispose of the controllers or the text editing controllers that we have right so for now we'll just create a login View and this will return a scaffold and just so that we can see what we are developing I'll copy this go to the main.dart file and remove all of this boilerplate code we don't need this counter application and instead of this we are just going to have constant logins View I'll save it and we should see a blank screen and here we are after having login view in place let me show you a diagrammatic representation so suppose this is our UI file this UI file is directly going to talk to the controller and this controller is directly going to talk to the repository files this repository file is basically the files that we are going to create in apis so it's going to be the Tweet API there's going to be user API and authentication API so these are the repository files all the backend related code but with this architecture this might seem very simple UI is talking to controller controller talks to repository but here's a catch UI cannot directly talk to repository and repository directly cannot talk to UI so in our login view for example we cannot have any API file being imported that's the best way to understand this if you're going to have auth API here you're not going to have the import of auth API over here because you're never going to use auth API in our login View we are going to use all of that in controller and controller will directly talk to the login view so you can have import of auth controller but not auth API so UI cannot directly talk to repository and repository will never talk to UI and make changes in it but yes UI can talk to controller controller can talk to Repository so let's put a crossover here because it's not allowed now you might ask what is the point of this controller why can't we directly have UI talking to repository as I said repository is going to contain all the backend related code and it's going to have nothing extra so it's just going to contain apprite server calls upright might give something to us we need to send it across to controller controller will do all the processes that are required like model conversion talking with other apis so that we can create one function for example if you want to edit the user profile you'll send a user model that needs to be updated to apprite which means we are going to send a user model to repository for files the repository files will make some changes and send it back to controller but controller doesn't have to stop there because edit profile also includes editing the user image and the banner picture the so the controller will also talk to the storage API which is a different API than user API and then the controller will make changes to UI maybe pop off the screen so this is the point of controller it is going to make some important changes to our function and another question you might have is why is API not in features folder right why is controller inside of authentication feature but why is API not in the auth feature like it should be there right and I partly agree with you but the problem is suppose we have tweet API and user API they're both very interconnected so some function or some functionality in our app might require user API and tweet API both in the controller and the logic of feature first approach is that if you don't want any feature you just have to delete that for feature and the app should still work fine for you that's the logic of feature first approach if you don't like anything if you don't like a certain feature so suppose you don't want tweet related features you can just delete that feature entirely by just deleting the folder so if we delete this folder and suppose user API or tweet API is required in some other feature that will be a problem because you have deleted the API solder along with it right that's why apis folder is created in the lip folder if you don't understand it till now don't worry when we get into the real code you'll understand this is all theoretical practical approach will give you a better insight so let's go ahead and design the login view now so this is what we are trying to develop now let's break it down and see what all components are needed first is this component which seems like an app bar with a Twitter icon over it okay we have the Twitter icon already installed or downloaded you can see that in assets svgs we just had the Twitter logo SVG over here so we don't need to worry about the logo part the next thing is a lot of space over here so we need to put some spacing and then we have two text fields that look identical that's the main thing they both look identical so we need to create One widget for them because they're identical if they're identical we don't have to write the same code again and again so we can just create One widget for it and keep reusing it right because this is just for the login screen even in the sign up screen we are going to require the same auth fields then we have a done button which is kind of circular in shape and then we have a text with some part in white color and some part in blue color okay now let's start developing it so in the app bar we're going to have the app bar but again app bar is going to be reusable because the login view has it the signup view has it even the home screen has it so let's create a separate widget for it so if we try to create another widget for an app bar let's see what we get so we are just going to have a stateless widget and we are going to call this reusable app bar and then we are going to return an app bar so in the lib folder we are going to create another folder called common and in this common folder we are going to have all the common widgets that are required in the app so the first one is the reusable app bar now we'll import material Dot then we are going to create a stateless widget and call this reusable app bar then we are going to return a scaf not a scaffold sorry an app bar and in the app bar we are going to have a title via title because the Twitter icon logo is right in the center and now we want to display an SVG to display an SVG we can't do image dot asset or something we'll have to use a new plugin for it and that is called SVG flutter SVG and now to use it we'll do SVG picture dot asset and now we'll mention the asset name we won't directly mention like this assets slash svgs slash Twitter logo.png no we are not going to do that because we have already created an assets constants file here we have it so we can just do assets constants Dot Twitter logo all right this is another benefit of having a constant file if you have to use it everywhere you can just type this without the scope of making any error because we know whatever we have put there is correct and if you want to change of course you can add another logo change the path over here and it will change everywhere you've used it you've just used it right now and you reusable but if you have a splash screen or something you can use it there as well now we can just take this R Bar put it in the login View and now you can see we are getting this error because app bar cannot be of the type reusable app bar which is a widget it needs something known as a preferred size widget that's why we cannot put app bar in a stateless widget what we need to do for it is go to the constants have UI underscore constants dot dot file created we are going to have class of UI constants and you are going to return a static app bar and now we can return the app bar from this function because it is of the type app bar so we can call this function and it will still work because it's of the type app bar and app bar implements the preferred size widget that's needed in this app bar type right so we can copy content from this app bar delete this file go to the UI constants and return the app barrier now we can import SVG picture import assets constants so make sure you uh import constants dot dot and done now we can do this so we can just call UI constants dot app bar we are not creating an object of UI constants instead we are just doing UI constants dot app bar because it is a static property if you want you can make this a non-static property and create an object of UI constants and then call app bar but I just think this way is better we can remove this URL it doesn't exist and restart the app and nothing shows up so let's see why one reason is that app bar is of the black color because you have mentioned that in the app Theme right here the app bar theme background color is black and elevation is zero so if we go to the main dot dot file app Theme is this theme that is present over here so the app bar is black in color so we cannot see anything Plus the logo here is black we need to change it to Blue so we can just do color palette dot blue color save it and now the Twitter icon shows up but it's quite small so we need to increase its height so we can just do height 30. save it and here the Twitter icon shows up it looks exactly like this but there's one problem if you open this on an Android emulator this title will go to the left we need to keep it centered every time on any platform so we need to path in a property of Center title true aware it should be outside of the title property Center title true now there's no changes but we are sure that this will work on Android as well we'll open the Android emulator when we are working on the Tweet feature but for now let's just develop on Android on iOS sorry another thing that I have problem with is anytime the login view is calling set state or when we are using riverpod you'll see that whenever the loading indicators are showing up app bar will keep running and that's not what we want we want it to not rebuild even during the loading indicator so what can we do well we could have created widget for it but we tried and it didn't work for an app bar that's why we are just going to have final app bar which is equal to UI constants dot Abba we are going to create an instant surveyor so that every time there's a rebuild it doesn't call this function again because we are just having the instance of app bar with us which we have called right here so every time the build function is recalled R Bar is not built now and if you save it it works the same thing but it's just a little bit of optimization now we need a body and in the body we are going to have a single child scroll view because we have two text Fields when we click on either of the text field we can get a render flow error by the keyboard so whenever you click on this text field a keyboard appears and it might minimize the screen and give you a render flow error we want to avoid that so we are having a single child scroll View and then we are going to have a child add a little bit of padding because padding is needed for all of these fields you can see the done button has a bit of padding both the text Fields have padding so we need the padding and padding is going to be Edge in sets dot symmetric by symmetric because we want it from the left and the right side so horizontal 20. and now we need child and the child is going to be column because we need four different type of widgets two text Fields so we are going to have text field one text field two button text plan you'll understand why we are having text pan here well just to say it simply because you have two different type of colors used and we want them in a same line you can of course use a row widget for it along with two text Fields but a text pan widget is better because we have to write lesser code for that so for the text field one we are going to create a separate widget because it's going to be reused and we are going to call this auth underscore field. we are not creating this inside the common widget or common folder why because auth field is only used in login View and signup view nothing outside of the auth feature we need different type of fields later on for example in edit profile we are going to have a different kind of field but not this kind of text field so let's import material dot we are going to add a stateless widget and call this auth field now we need to return something known as a text form field you can even use text field doesn't matter in this case and then we are going to have a controller so we'll get the controller from this Constructor why are we getting it from The Constructor because if you use auth field like this area we need to reuse it right so we can again call auth field and if we use one single text field both of these will have the same text passed in so if I write something over here in this text field it will automatically type it in this field because they both have the same controller we don't want this to happen so we are asking them to provide us with the text editing controller themselves so that we don't have this problem so we'll import this controller and pass it in now we need to add a little bit of decoration so what is the decoration we need well there should be a border and whenever the text field is clicked on it should have a blue Highlight and of course some padding in between the hint text like email address and the increase in font size because the initial or the default one is quite less so we can do all of that by having decoration input decoration Focus border Focus border with outline input bottom the focus border is basically whenever you click on this text field what color should show up so whenever you click on the text field you want the blue color to show up and it should be an outline so we are having an outline input border then we want the Border radius to be not exactly a rectangle but there should be a little bit of curve so we can have border radius of Border radius dot circular 5. then we are going to have a border side of constant Border Side with color AS Palette dot blue color so let's save this pass in and create controller first of all so we are going to have final email controller is equal to text editing controller and then we are going to have final password controller is equal to text editing controller now we just need to dispose this off and then we are going to have email controller.dispose passwordcontroller.dispose all of this to the auth field so we'll have controller email controller controller password controller and if you want to see what I said if we have both as the same controller they'll have the same text let's try it out so I'll just say AAA and you can see both have the same text and if I change this to password controller both will have different text now but you can see our Focus border is now perfectly working whenever we put a focus it has a blue line but it's not thick enough so we need to make it thick and of course there's a little bit of less padding here so we need to add the padding as well so the width is going to be three over here save it and you can see this is much thicker now this might not look exactly like this one but when we increase the padding so let's do that so here we are going to have content padding which should be constant Edge insets dot all 22. this is a tried and tested value I kept on increasing the value and saw what fit the best so if you have anything else you can try it on your own and this has a little bit of more padding now I just need a hint text so the hint text is going to be whatever the login view provides I cannot just say this is email or this is password because it will show up for both the text Fields I don't want that so I'm just going to import that from here so we have hint text required this dot syntax take the syntax and pass it in we'll pass in the hint text wire which is email and this is password of course this is a named argument so we'll pass that in save it Let's ignore let's put the warning aside by putting a const and here we have the password and email showing up now we just need a focused border now that we have focused border we want the border that shows up even when we are not focused so we can add that by having enabled border so we can just copy this paste it replace this with enabled border so this will show up even when we are not focusing on the text field and this should be of the gray color we can save it and see there's too much width so we can remove the width part and now we can see this looks cool but it's not quite there we need to put it in the center so we can go to the login View wrap the single child scroll view with something known as the center widget and if you're wondering how I got this option I just clicked over here command shift R which is a refactoring tool if you don't have this you can just do right click refactor and then click on the center widget now you can save this and here it is right in the center now both of them are very attached to each other so we want to give it a bit of height so we can just have constant size box of height 25 so now both of them have some space in between now you might think that yeah the text fields are very down below but as we add more widgets this will keep going up so for example if I just take this text field or sorry size box and add a height of 40 here we are even when we click over here this works well but you can see the text field still feels small the reason for that is because of the font size you can see the font size is quite small not as quite big as this so you can just go to the auth field and what do we want to do we want to increase the font size of this hint text so we can find something like hand style and then we can use textile on it pass in the font size which is 18 and put a constant over here and here it is now this looks proper now we can go to the login view again and the next thing we need is this button the done button so we can create that in the common folder this is because we are going to need this rounded button later on in some other part of the application so I'm just going to create it and I'm going to call this rounded small button Dot of course you can name it in a better way but this is what I'm naming it I'm going to import material dot I'm going to create a stateless widget and call this rounded small button and here we're going to have a final void callback of ontap and this is needed because we want to require this dot on tap from the widget we are going to use this widget in similar to what we had done in the auth field we imported all of this we're going to require all of this as well and we are sure since this is a button this is going to have different on tap now there are different ways of creating this more rounded small button but the way I'm going to use is I'm just going to have a chip widget I'm not going to really have any button we're going to have a chip widget widget label and this text is again going to come from the Constructor so we can have final string label require this dot label and pass it in now I can save this use this rounded small button in login View so I can replace this I'm going to pass in the ontap as empty function for now and the label is done save it and let's see what we get this is the button looks quite similar but there are a few few things that have to be changed the background color for example should be white and the font color in there should be black so for the label or more like first we'll configure the background color the background color should be the color here and we're going to take this from The Constructor as well if you're wondering why this is because if you're wondering why why cannot not directly use palette dot black color this is because this rounded small button is going to be used in some other widget and they might need some other background color some other font color so we cannot directly mention it over here so we can have final color background color and since we are here we can create another one which is font color or the text color now we can copy this have required this dot background color required this dot text color now we can pass in the background color here and that label or the text color is Style textile color is text color and this should be it so we can go to the login View pass in the background color AS Palette dot background color and font color or the text color sorry that is going to be palette dot white color right as you have decided we are just putting it here so that we when we have to use this rounded small button somewhere else that won't be a problem and if you want to minimize the code what you can do instead is just remove both of this go to the rounded small button and say this is not a required field whenever the user wants to change this background color they can just do that by having it mentioned explicitly otherwise it will just be palette dot background color or palette Dot white color so if this is used in some other widget and this widget needs some other color then they can explicitly mention that yeah the background color should be palette dot blue suppose and the font color should be white only so if you have minimized the code that we need to write over here so let's restart it and see here is a button and it's quite the opposite of what we wanted so let's just replace them we want the text color to be black and background color to be white sorry about that so this is what we wanted now we have this button now we just need to increase the font size and there's a bit of less padding so we need to increase that so the font size should be increased so I'll just put it 16. again this is a tried and tested value and there should be label padding so we can just have label padding constant Edge in such dot symmetric from the horizontal Direction I need 20. I'll save it now this looks very absurd I want an increase in the vertical padding as well so I can just do vertical five save it and here you can see both of them look similar but this button is in the center I want it in the right hand side so for that I can go to the login view again wrap this rounded small button and a widget known as align this align widget will help us align the surrounded small button so it will help its child widget to get a line and we want to align it to alignment dot top right save it and here we have it looks good now we need to leave some space and add our text pans so I can copy the size box remove this command and now we are going to have a rich text by we having Rich text because text span is not really a widget it is a spam and in this Rich Text we can add multiple spans for example if you look at this this requires inline span this is where our text pan is going to be there so we can just have text span and in the text Pan the text is going to be don't have an account so let's see what we get with just this much yep we have this we have been referring to the sign up screen all that time but this is going to have don't have an account because we are on the login screen if you're on the login screen and if you want to go to the sign up screen we don't have an account so don't have an account then we are going to have in the children a text pan and in the text pan we are going to have a text called sign up with a space aware the space should be mentioned over here because there is a bit of spacing here if you don't add space both of these texts will be stuck together so we have sign up let's save this much here we have it we just need to change the color of this text fan so we can just have Style textile and textile should have a color of palette dot blue color and font size should be increased to 16. and the same thing should happen above as well the font size for this text man should also increase so you can just put it over here that the color is the normal color what you're showing but the font size should be 16 and both of these font sizes should match because they are on the same line one having a bigger text and another having a smaller text would look very absurd and here we have it looks word now we are getting all of this warning so we can just add a const but we cannot add a const because this requires a recognizer so whenever the sign up over here is clicked we need to navigate to the sign up screen that's why we are going to have a recognizer and this is going to be tap gesture recognizer dot dot on tap this is the syntax tab just a recognizer dot dot on tap and whenever the on tap is made we need to call this function this function will be called and whatever you want to do we want to navigate from this screen to the sign up screen so we can add that when we create the sign up view now we can just put constant over and save it so the login view looks correct similar thing will be needed for the sign up view so let's quickly do that so we'll have sign up underscore view dot dot import material dot create a stateless widget actually stateful widget of sign up View save it now we'll copy all of this we are going to import the constant so we can just import constants dot dot and I think constants doesn't export UI constant so we can do that so we can export dot slash UI constants dot dot and we can fix this in the login view as well we want to import constants dot dot again coming back to the signup View we need to return stuff so we can just return this scaffold import the palette so we are going to import theme dot dot we're going to import flutter gestures package so that we have tab gesture recognizer we're going to import the rounded small button and actually instead of directly importing it we are going to create a common dot dot file over here as well so we are going to export dot slash rounded small button for now so we can come over here import this and import comment dot dot so that you know we'll import lists of other features so if anything else is needed in this screen we just have to import them there because the common dot dot is already present it will import all of the things that have been exported from here now we'll also import auth field so let's import it and this looks good now just to see this on main.dot let's change this to sign up view and let's go to the signup View and see what changes need to be made well email and password are the both the fields that are needed done is also there now we just have to change this to already have an account so we have already have an account and we want it to be login so we can just pass and log in and here we have it now whenever the user comes first time to this application we either want to show the home screen if the user is logged in or the sign up screen because it's the first time they are entering the application so this sign up view is going to be the screen that will show up in the main.dot for now when we have the home screen we'll put the logic of adding the home screen over there now what you want to do is whenever we click on this button we want to go to the login View so we can create that right now so here in the sign up view whenever this is clicked the on Tab you're just going to have Navigator dot push and we'll pass in the context then material route material page route then we are going to have context and then we are going to return the login View and this is going to be a constant now this is a lot of code to write the material page route so what we are going to do is just copy this or cut this go to the login view create something like static route for this and return a material page route right so now what we have to do is just login View dot route so we don't have to use this long boilerplate code every time we need to navigate from sign up to login or suppose we are logging out so we don't have to do this in the home screen or the other screen as well wherever the log out operation takes place we just have to do login view dot route and it works fine now the same thing is needed for the sign up view when we move from login to sign up view so in the on Tab we are just going to have this and then we are going to go to the sign up view actually let me just copy this route put this in the sign up view and just return a sign up view over now we can go down and pass in sign up view dot route now when I click over here nothing happens so let's restart the app if I click over here I go to the login view how do I know that because your signup shows up and if I go where the sign up button shows up that's pretty cool now that both of these things work the next part is making the authentication part work so whenever we enter the email address and password and then click on done we need to create a user and then send them to the login screen and then the user should be able to log in with the same credential and if it's a different credential we should show them an error but before doing all of that we need to install the main package that will drive our entire app which is the flutter riverpod package because all of the connections everything is going to be made through real pod and it's going to be very easy and I'll explain every step that needs to be taken and why we are doing what we are doing so let's get started with it right now so let's install the flood arrival pod package so I'll just add flutter River pod make sure you have flutter underscore report not just report riverpod packages for Dart packages and Dot code but flutter report is mainly for flutter SDK so make sure you install that and now in the apis you are going to create our first API which is the auth API dot dot and first of all we are going to create an abstract class and this abstract class is going to be called I API I auth API sorry and what is this abstract class for well this abstract class is going to contain all the functions that are going to be present in our main class which is the auth API class which we are going to implement so we are going to have this so whatever function we pass in here the class is going to have its implementation present over here why is abstract class needed because this is because for many reasons two main reasons I create an abstract class because abstract class contains all the functions related to a particular API so example the auth API will contain all the function signatures of that are required so for example if I want to sign in I'll have suppose avoid sign up function right now I get an error over here I can just do command full stop create the missing override that's needed because I'm implementing iot API and then I can do my signup process here this is required so that in case I want to change my backend from app right to suppose Firebase or node.js I can just delete this auth API class entirely so that there's no Firebase implementation and I can just have class auth API again ex implementing I auth API right now I will get all the missing signatures or the missing implementations I will create them and write my code from scratch I still have all the functions that are required for my application but the implementation will be different so I can easily change my backend from app right to some other database this is very useful another place where it's mainly used is in testing so if you want to test a bunch of functions and you don't want to forget which function to test out you can use this abstract class and implement it and if you're wondering why this is prefixed with ie this is basically interface this is an interface for the auth API class so this is why we have the abstract class it's very handy and you understand its main purpose when you shift the backend if you want to anyways let's just delete all of that we are not going to have this function signature we are going to have it a bit differently what is the difference well this auth API is just containing upright code there's nothing else going to be present so we don't know if it's going to be a success or a failure and even if we know that we want to send it to the controller that yeah this is the success so if it's a success this is the data and if it's a failure what is the error message so for that we need to return two data types as of now that doesn't support returning to data types it's a work in progress I'll mention a medium article where it shows that it should be out in the mid of 2023 but as of now it's not possible so what can we do well we can install a package known as FP Dot and if we install that FP dot package will be able to return two types of data types so if it's a success we are going to send that if it's a failure we are going to send another thing and that will help us a lot and it also provides us a bunch of functions to handle those success and error messages so if it's a success it will give us a very useful API that we can use and bypass the boilerplate code that we need to write again and again if you don't understand don't worry I'll explain it to you right now so suppose we want to return a success and a failure right so if it's a success I want to return the account of the user so whatever data is present like the current account of the user this is something apprite gives us and if it's a failure I just want to return a string so I can do that by having either this is something given by FB Dot and then if it's success I want to return account and if it's a failure then I want to return string so in case so it will either return account or it will return string that's the main purpose and then we can have the sign up process so we will sign up and obviously we need to require the email and the password of the user so that we can sign up the user so we'll have required string email required string password but this is obviously not going to be either this is going to be future either because app right is going to connect with our back end so upright client that we have the package it will connect us with the app right server so it will take some time that's why it's a future so we will have future either account string because we are going to use async in there right this is a pretty big thing to write and this will be happening even in login function and several other functions we don't want to continuously write such a big type definition it's a time and resource waste so what we can do instead is create a new folder in lib called core and this core folder is going to contain all the essential things for example we are going to have something known as type definitions over here type def dot dot and this is going to contain all the type definitions for our app so the first type definition we can create type definition like this type definition is basically creating our own type like future either like them so we have future either which is equal to Future and we'll pass in either just like we did before but this time I made a mistake previously when it's a failure we'll return string and if it's a success we are going to return account this is for the failure and this is for the success not the other way around then we'll import the FP dot package and then we are going to return failure and in case of success we want success but what are these failure and success classes so we are going to create failure class first of all so we have failure dot dot so we'll have class failure final string message and final string not string stack Trace stack trees so that you know the failure contains the message what message needs to be displayed and the stack trace and even you you can even have the hash codes and whatever but you're just going to have two of them and we don't need the named Constructor we are just going to have positional Constructors over here and we can mark this as a constant great so we can go to the type definition import failure package from core but again in the core we are going to have something known as code. we are going to export failure dot dot we're going to export type definitions dot dot that's it and now we'll import failure so let's import failure we are not importing core over here because we are in the same folder as of now and for the success it really depends if it's a success here you can see we have to return an account but somewhere else we'll have to return suppose a map or some other data be or some other data type app right has to offer so this really depends on where we are using it so we can just do this we can pass in a generic type T over and then we can pass T over here now if you don't understand this no problem I'll show it to you over here now if we use future either you can see we have this now the sign up function has a type of future either failure Dynamic this is exactly what we had written away a future either failure but this is now Dynamic why because we have not mentioned anything over here now if I mention string over here the success type over here is now string since it continuously varies I have mentioned the success type over here so somewhere it can return account somewhere it can return map somewhere it can return string and this function will have the appropriate data type return correct now let's create a few more type definitions another type definition is Future either void which is equal to future either y what does this mean the success data type is void basically if it's a success we don't want to return anything we just want to let the controller know that yeah it's a success you can move forward and another data type that we can have is type definition future voi not future either white just future void which is equal to Future void this is basically eliminating the usage of future generate generic type but if you want you can keep this otherwise you can just remove this doesn't matter so we can remove FP Dot from here we don't need that because we are importing type definition and we can even import code or dot now since we have exported type definition from code.package cool if you didn't understand I'll again brief you through it basically we have code. we have exported type definition and failure dot dot now failure has this class which has a string message and a stack Trace so that you know if you want to debug we can just do failure dot stack trees and it will give us the correct structures and then we have the type definition where we have mentioned two types and in case of success we have taken it basically from wherever we are calling it now we have returned for success as account aware but there's one thing to note in app right there are two accounts over here one is the account from models so if we just remove this and go to the account model this is the account model and this is basically a simple model the user uh account class which requires have from map to map functions just like we're going to create our models and it implements a model right another one is from the service class this allows us to authenticate and manage a user account so this is a service and this service will help us to call sign up login functions so we have get function over here which will help us get the user account it will get us the create method which will help us to create an account and update email and all of those so this is related to service but the other one was basically a model that was returned to us in case you want to get the username the user email and all of those stuff you can see that in the get function it is returning to us models.account models.account is basically this model right so this was a difference and this is very important to note because sometimes you'll by mistake import the models and the service both and you'll be confused as to why we are not getting any autocomplete features or error so if you just import models you can see it gives you an error because it is defined in both of those places it's the same account but one is from service and other is a model what do we need in this case when we sign up we should be getting the model of the user right when we want to sign up the user we'll be using the account service let me just simplify it when you want to sign up or you want to get the user account you'll be using model dot account and when you want to you will be using account which is coming from apprite.dot or service account you can just call it that and when you want to access the user data then you'll be using model dot account so we can prefix this as model so that there's no confusion and now we can have model dot account aware because we are signing up the user after signing up after we creating after signing up the user that means after creating the user account it will give us a model account and we can return that to the controller but when we want to get but when we want to sign up or create the user then we'll be using account if it's not clear don't worry we'll see the send code right now so I'll again have class auth API which will Implement I auth API and we are going to create one missing override it has everything in it we'll call this asynchronous and now let me demonstrate the difference to you exactly in terms of code so we are going to have final account over here which is a private variable because whenever we do auth API we should not be able to access account like this right that's why we are having a private variable now we'll create a Constructor for this which will be required account and we'll set this account variable to account that's received from The Constructor basically this is a private variable we are requiring this account which is a new variable which is not private because it named Constructor you cannot have required this dot underscore account it will give you an error so you have this and you're finally assigning the private account variable to the account variable that's coming from the Constructor I hope that makes sense the whole point of all of this is just so that your class has this as a private variable and its instance is not available outside of the class now to demonstrate the difference to you between account model and account service we can just have underscore account which is the service one dot and it will give you a bunch of options create create Anonymous session this means account service is related to creating and managing the data in the server side in the app right dashboard but on the other hand if we have model dot account let me have model dot account you can see if we create an instance of this we get email email verification these are all the user related data and that's what I'd said above if you want to sign up or want to get user account you can use simply account which is service account and if you want to access user related data there's model.account I hope it's clear now if you're not just play around with it a little bit and you'll get a great understanding of it now we are just going to after I catch because there's a scope of error we don't know it's not really an error it's an exception so we are putting this in a try catch block and now we'll catch account Dot create and then we have three fields to pass an email password which has already been passed in and the user ID do we have the user ID well no the user ID is a randomly generated unique ID so we cannot have that so for app right to create it uniquely what I can do is put a string and have unique type 10 over here if I do this much app right will generate a unique ID for this account if there's another Syntax for it called ID dot unique and this does the same thing if you just click command full stop you can see it just Returns the same string we entered over here before so you can use either of these I'll just go ahead with this because there's less scope of error even if there is a little bit of error scope and if you see a wire it's returning to us an account and this account is model.account we need to return this to the controller so we can just have final account which is equal to await account.create now we have account in our hand we can just do return account right no this is because the data type this is because the return data type of this function is future either failure or account in case of success we have to do something like this we have to return right and then pass in an account variable inside of it this is something given by FP dot itself so if it's success we let them know that they are this is the success variable and this is the data you're getting when it's success if you try to pass in something like a string it will give you an error because argument type string cannot be the assigned to the parameter type account so you need to pass in an account variable over here now in case of failure we'll just do return left because it's a failure we'll return left and then we can pass in e right no because in case of failure we have to return failure class and then we'll pass a message as e.2 string and stack Trace which we get from catch function here we'll pass in the stack Trace as well so this is it this is the function to create a user account in apprite dashboard but there's one other thing you can do to improve the exception handling over here which is catching on app right exception so we have on app right catch e stack Trace and then we are going to return left over here as well but this time since it's an upright exception this is of the type upright exception not object so we can access some methods given to us like e Dot message and return that but it's giving us an error because e Dot message gives us a string and failure has an acceptance of just string so we can just have something like this done where we say some unexpected error occurred and the stack Trace is as it is so if it is null we are going to return some unexpected or error occurred otherwise we are just going to have e Dot message passed in so this is the entire function I hope you understood the difference between account and model dot account if you didn't you can rewind it I've spent a lot of time on it already I wouldn't like to spend more on it anyways we are done with this now let's use the provider package to provide this class now let's use the Riverport package to provide this class so we can just have final auth API provider which is equal to provider this provider class is given to us by rebapod itself and Report gives us access to refs so what is this thing provider lets us provide a single instance which is immutable so if you try to change the value of this auth API provider later on in the future it will give you an error there are multiple types of providers in riverpod like provider this one future provider stream provider State provider and state Notifier provider there are two other types as well Notifier and async Notifier but you're not going to use that in those in this tutorial so what is the difference between provider State provider and all of them provider basically provides a read-only value you won't be able to change its state any time so if you return this auth API class from your and pass in the account which we will do you cannot change the value to return something else later on in the app it will just be a read-only value State provider and state Notifier provider help us to change the value later on in the app we are going to take a look at them but for now let's concentrate at provider another two types that I mentioned future provider and stream provider we are going to use them extensively in this application because apprite is all about Futures and streams other question that you might have is why are we using provider here why can't we just use auth API class like this everywhere right now I will agree with you you can use that but with provider it becomes better in bigger application because you don't have to create an instance so suppose you have to instance auth API class over here so if you use this in some place you'll have to also import account provider and now if you have to create account like this then you'll have to also pass in the client and for the client you'll again have to pass in client like this there's a lot of things to do and even in the client you'll have to pass in suppose like the end point if you want a different tree or self signed if you want it differently there's a lot of work to do so instead of doing all of that we are going to create separate providers for each one of them including auth API provider you don't want to include this auth API class every single time you use it right it has a lot of code to write provider will minimize that differently also provider caches all of this so it won't create a new instance of this auth API everyone else every single time it will just cache it and give it to us so that helps in memory efficiency as well so now that you have understood this we can go in the core and create something known as providers. this is going to contain all the upright related providers or any other provider in our application that is not related to a class for example this auth API provider is related to this auth API class so if you want to delete all the API at a certain point we can just delete this file and everything related to auth API goes away so we are not going to have auth API provider in providers. we are going to have common kind of providers which is final upright client provider which is equal to provider ref where if should be small this ref is basically provider f it will help us to interact with other providers you'll see an example of it in just a minute let me just first complete this now we are going to create client variable so we have client client equal to client this upright client provider will be used in suppose account provider and database provider in a real-time provider all of the functionalities that apprite has to offer so it's important for it to be created as a provider then we can just return client dot set endpoint and we already have the endpoint with us don't forget we have apprite constants so we can just return its endpoint so we have app right constants dot endpoint dot set project and we need to pass in the project ID over here so that it can make the connection with upright dashboard so what is the project ID we have stored that so we have apprite constants dot project ID dot set self signed status of which should be true this is for the sell sign certificate and will be used only for development this code can be found on their documentation or when you complete the platform part we had this all of this written so you can copy it from there I just wanted to demonstrate what every function means so I just rewrote it now we will create final app right account provider so we have account provider which is equal to provider ref and now we will return account right and this account should be from upright.dot not the model one remember that I've explained to you why now we need to pass in the client so we need this so what we can do now is final client is equal to ref dot watch upright client provider so this is where ref helps us I said it can help you to interact with other provider so this ref is helping me to interact with other provider in the app right account provider I'll repeat that this ref will help me to interact with other providers using ref dot watch or ref dot read the difference between ref.watch is that it continuously watches for any changes in provider and ref.read is just a single time thing so it will just read it once the first time and then it will stop keeping track on it I'm keeping watch because in case I want to change any of the dependencies here and if I click on save it will automatically show that on the screen whether F dot read that's not possible we'll have to restart the entire app from here but you can use any of them it really doesn't matter unless you don't want the hot reload feature or the hot restart feature so this is a app right account provider we'll go back here now we need to get account so we can just do ref again and again dot read or dot watch I'm going to do watch and I'm going to watch the app right account provider if you do app right client provider it will throw an error because it gives the type of client we don't want client we want upright account provider so just to minimize the complexity if I just cut this paste it over here so we have final account is equal to ref.watch and check this this has the type of account so watching this will give us the type of account now we can take this account and paste it over here so we have the auth API ready with us and that is why we are using providers it minimizes the work to be done by a lot so anyways let's get started with the controller part we have created the API we are just having apprite calls over here now in the auth controller dot I'll call this function and print the name and the email of the user so that we know that yeah whatever was done was correct and then later on we'll check in the app right dashboard as well and after that we can test this on Android emulator as well because there is a certain problem in Android which you'll face so the auth controller over here is going to be called auth controller but this is not all it this app right controller is going to extend something known as a state node F5 as I already mentioned riverpod has multiple providers the second one is State Notifier provider provider was used when you wanted to provide an instance of the class or you wanted to provide a read-only value a value which cannot be updated but with auth cont this state node of fire we will expose a value which can be updated and which can also be read so this is an upgrade over the normal provider and here we are getting an error because we have extended state notifiers I'll press command full stop create a Constructor to call Super I'll remove this because super should be called over here and what is all of the super and stuff so here in the state Notifier you might see that we need to mention a type a generic type what is the value that will be changed and for us it is a Boolean value why because we want to add something known as is loading so if our app is loading so suppose we click on the sign up button and the data is being stored to apprite server the loading indicator should show up in that time and that's why we have the Boolean value of is loading so initially the is loading part is going to be false this Boolean value indicates is loading variable for us initially it should be false now whenever the user creates an account so we'll avoid sign up and this controller is going to require string name String email not name sorry it will require a password so we can have email password and also build context why build context because in case of error we want to show a snack bar and the Syntax for snack bar is scaffoldmessenger dot of context it uses build context so we need the belt context but note that we can use build context and everything inside of a controller because we don't want to test it but we cannot use this inside auth API because this class is what we want to test of course I'm not including that in this tutorial but controllers are not tested in this application only auth apis are or anything related to apis are so that's why I can use build context here however if you want to test the controller as well you'll have to require you'll have to remove the build context call anyways since I'm not testing this I can have build context over here and now what I'll do is State equal to true what is State equal to true well state is basically of the type Boolean and it is Boolean because I mentioned over here Boolean state is basically is loading value you can consider state as is loading it's just named a state because this is what a riverpod has to offer but this is basically our is loading variable so right now when the user clicks on sign up button this function will get triggered and when this function gets triggered is loading becomes true so we start to show the loading indicator and then we start a process what is the process well we just call final response is equal to a weight so we need async why are we awaiting it because we have something known as auth API this thing exactly we need to call this so that we can create a user account so here I'm just going to have an instance of auth API and it's going to be similar a private variable just like this one and we are going to require this as a named argument so we have required auth API auth API and underscore all the API will be equal to auth API we have known this already now we can just use underscore auth API DOT sign up after we do sign up we have to pass an email and password we have already passed that because you're getting this from the function parameters now if you hover over this stress it is of the type either failure account now how do we get if it's failure value how do we get the value if it's success value how do we get the success value well for that we can call response dot fold this is one good method FP dot provides us so that we can efficiently handle a failure and a success L is basically the left value and R is the right value so our left value is a failure class and right value is the account variable or the account model so in case of success in Failure we want to display a snack bar in case of success right now I just want to print r dot name r dot email whatever and in case of failure um what do we have to do well I want to have a snack bar so I can just have scaffoldmessenger dot off snack bar and all of those stuff but it's a lot of code to write so I'm just going to create one function for it so that I can reuse it every single time so you can go to the core folder create a file called use tilts.dot and here have your first function which is Chino snack bar it is going to have multiple utility functions as well like other functions pick images pick image all of those functions but we'll create them as and when we need them so for the snow show snack bar we are going to require two things one is the build context and another is the content and here we are going to have scaffold messenger dot of context dot show snack bar and here we'll pass in the snack bar all the code that's required to create a snack bar this is all that we need now I can take this I've not created a class for this because it's a normal utility file I just want to call this function without calling the class that's why I've created this as a global function now I can just call show snack Barrow here pass in the build context right here and the content which is the text and the text is l dot message since it's a failure class I can access the message property on it but of course if there's some problem we can also print l dot stack trace and it will give us the entire space of where the error is happening and all of those stuff now I'll create a provider for this auth controller class but just creating a provider is useless because we are extending it from a state Notifier so we have something known as a state Notifier provider let's create that but before creating that you might think that it's a lot of boilerplate code to write even with riverpot to minimize that you can go to the extensions tab in vs code and search for riverpod Snippets and you can go over here and install the one by Robert Browning after you install that you can go to the auth controller just type State Notifier provider and it will give you the snippet for the code now you can type the name so the name of the provider is auth controller provider now you have to mention the type of error because earlier it could Auto detect the type if you hover over this Auto auto detected that this is of the type auth API which state notify provider it cannot do that it can detect one type but we have to pass in two things first is the type of the class that we are returning from the state notify provider we are going to return the auth controller class from the state notify provider and another is the type that we have mentioned over here which is Boolean so we have Boolean and now we can return auth controller and that's it now we need to get instance of the auth API class and I hope you know how to do that you can just do ref dot watch auth API provider and we are done we have created a system of efficient techniques so that we can just do some simple lines and it will work for us so we created a state Notifier provider because we had extended it from State nodifier we typed in the class the auth controller class and then we passed in the Boolean data type because that's what we had passed in over here if you remove this Boolean it gives you an error over here because you'll have to remove that and you'll have to pass in Dynamic over here because if you don't mention anything it's dynamic but we want it to be Boolean so that we get nice autocomplete features later on what is this later on well it's in the login view itself so if I go to the sign up view sorry and call a function so we'll have void on sign up and we'll have ref but we cannot use ref aware why because there's nothing like ref variable or anything layer so what you have to do is come over here press command press command over here come over here press option if you're on Mac and select all of these three things stateful widget State and State and pass consumer to it now click on command full stop and import the flutter riverpod Library we have converted the stateful widget to a consumer stateful widget this consumer stateful widget will give us access to widgetress what is widget ref well we saw provider ref provider ref helps us to interact provider with the provider but widget ref helps us from widget to a provider so now I have again access to ref why do I have access to ref over here because consumer State gives us access to something known as ref if you just come over here you can see it has something known as widget address so I can use that and called read method on it whenever we want to call a function from a provider we'll always use read you can get a more description over here reads a provider without listening to it avoid calling read inside build if the value is only used for events event is what I said when you read it you only have to call functions on it if you use this instead if you use ref inside of build function not in any functions if you use this inside of build function you need to use ref.watch if you're using it in any of the functions like over here you have to use ref dot read now what do I want to read I want to read auth controller provider don't do auth API provider because I said you cannot have auth API files inside of a UI file so we have auth controller provider dot Notifier when you use nodifier you get access to the class instance and then you can use the sign up function however if you don't use Notifier you won't get access to any of the methods why let's see the difference if we use final risks is equal to this and however this this is of the type Boolean why when we did this with provider it gave us the instance of auth controller provider or the auth controller class right but when using res it gives us Boolean well that's because of the difference between provider and state Notifier provider in auth controller we have used State Notifier provider when we just do ref.read or ref.watch auth controller provider it gives us a Boolean value which is the is loading value but when we want to get instance of the class we have to use ref Dot read auth controller provider dot Notifier I know it's a bit overwhelming but as and when we build more functions and use more of these riverpod techniques you'll understand why we are doing what we are doing and you'll get an intuition of when to use what so as of now we'll just use dot Notifier because we want to get instance of the class if you hover over this this is of the type auth controller now and now I can call sign up on this method now we have to pass an email so I'll pass an email controller.txt password will be passwordcontroller dot text and the build context build context is provided in the consumer State itself it's like the state property but it has context as well as widget ref with it now I can take this on sign up function go down and put it in the or done button so whenever the done button is clicked I want this to run and it should create something for us now before running the app there's one last thing we need to do go to the main.dot file and wrap my app widget with provide a scope provider scope is another widget provided by flutter riverpod package this provider scope keeps track of all the providers that are declared because these providers are declared globally in our applications you can see that it's declared outside of the class this provider scope will keep track of each one of them and if you are afraid of global variables like they can be updated from anywhere in our app and there are a lot of concerns with global variables don't worry about it because these providers are immutable so now I can take this const and put it beside provide a scope and remove the unused import of login View if you don't put this provider scope it will give you an error in the debug console now let's restart the app and see what we are getting so I'll just sign up the user so I'll pass in the test one two three at the rate gmail.com pass in the password as test one two three click on done and it doesn't work the reason for that is in the rounded small button we have taken the void callback on tap but we have not added that anywhere so we need to wrap this chip with a widget known as Inkwell you can also use gesture detector instead but Inkwell will give the nice Splash effect that I need and then I have on tap and in the on Tab instead of passing an empty function I'll just pass in ontap which is from The Constructor now I'll restart the entire application come over here and start so I've tested gmail.com pass in test123 click on done and still nothing happens here you can see it's giving us an error missing plugin exception no implementation found for all of this whenever you get this error this is probably because you've added a new package a new dependency to perspect.aml file but you have not restarted the entire app so you need to restart it without debugging and now after this is done let's try it again all right so our app is now complete let's come over here pass in the email which is test at the rate gmail.com password test123 click on done and you can see invalid password password must at least be eight characters so I'll just pass in four which makes it eight characters and then click on done no error and here you can see it's giving us nothing well that's because if we go to the auth controller we have printed the name there's no username there's user email so you have to print in the email and now let's see if I try to do it again it should give me an error because the user already has been created so if I click on done a user with the same email already exists in your project so I'll just have a different email and then click on done and here you can see we get the correct email now if we go to the app right dashboard as well then click over here go to authentication tab we have two users created tests are very gmail.com and test one at the rate gmail.com if you maximize the screen you can see the status the email is not verified there's no name there's email there's no phone number you can enter the new password from the dashboard the user preferences the key and the value you can have the objective for this is written over here you can read it and you can delete the user as well the user ID is also over here and this is a uniquely generated user ID I told you it will generate uniquely if I just mention unique in the auth API right here and if you just paste it you can see this is a different user ID a randomly generated one and this will differ from the test at the rate gmail.com so we can be sure about it all right now that the user has been created and everything works the next step is to log in the user with the same email and password if the user exists so we have to create a function for login but even before that there's one thing if I click on done there's no indication of loading indicators even though in the auth API we have set in the auth controller sorry we have said state is equal to True is loading is true so why is it not showing well because we have not watched it so in the sign up view we have to go here get the is loading value how are we going to get this we've already seen that we have ref dot watch auth controller provider now if you hover over this this is of the type Boolean because it's the is loading value so if the data is being loaded what do we want to do we want to show a loading indicator to do that we are going to create a new widget in common called as loading underscore page dot dot we're going to import material Dot we're going to have a stateless widget called loader which is going to return a center child circular progress indicator and this is going to be a constant and this is the loader widget we are going to use but why have I named this loading page this is because we are going to create another stateless widget called loading page we're going to extend the stateless widget but this time we are going to wrap it with a scaffold and in the body we are going to have a loader and this is going to be a const scaffold this loading page will be required in main.dart file when we want to show the loading page this is just a loader which can be used in some other pages but we want our own page of loading to show up we'll use this so here we can just have loader like this so if it is loading we'll get a constant load up otherwise we have all of this and now you can see we are getting the loading indicator continuously why are we getting this loading indicator well that's because we had clicked the button the is loading state has started so in the controller we have state is equal to true but we have not put state is equal to false anywhere that's why it continuously keeps on loading so here we have to have state is equal to false now if we restart the app pass and test at the rate gmail.com test123 4 click on done it gives a loading indicator but as soon as there's no error or there is an error it will stop the loading indicator so I hope you have understood the entire process you have state Notifier provider we have state Notifier we create an account using auth API we start the state so is loading is set to true if it said if is loading is set to true and we are on the sign up view we are constantly listening to it using ref.watch if you just do ref dot read it will not work for you you have to do ref.watch ref.read is strictly prohibited by using River pod and the build context or the build function now whenever is loading values changes we'll check is loading if the variable is loading then show a loader otherwise the entire widget tree I hope this process was understood if it's not I would recommend you to watch this entire thing or Analyze This code because this is the very foundations that we are going to use in literally every single file if you are overwhelmed by all of this don't worry when we create more files when we create more functions you'll get a hang of when to use what and I'll be sharing my thoughts on the same every single time so anyways now that this loading part is also done we are going to create the login function which is very similar to the sign up function so in the iot API we are going to create a login function now so similar to the sign up function we are going to create the login function here but yeah it's not going to return account it's going to return something known as session whenever you log in you get a session and whenever you sign up you get the user account that's how apprite works so here let's create the missing implementation and actually I'm just going to copy something from the sign up function here so I'm just going to copy this entire thing because everything is very similar I would recommend you to write this so that you get a practice I've already written it before so I don't find the need to practice more but anyways we have the Creator but this is for sign up to sign in you have to do create session and create email session you have to pass in the email and the password that's all here you could have passed in the name attribute as well so that when you do r dot name in the auth controller here you don't get blank space but we just having email and password name is going to be saved in the database this is the authentication console nothing is getting saved in the database if you just come to the upright console this is the database part and nothing is being stored over here everything is being stored in the authentication tab as of now so here we have created the email session this gives us a session so let's call this session and we will return that session so when we do create it will sign up for us it will just create an account in the upright console but it will not log you in to log you in you have to do create email session and that's all that's needed for login function pretty similar now we can go to the auth controller and declare this so I'll just avoid login and it's going to be very similar to this so let's just copy this paste it in here this is going to be async then we are going to have all of this stuff as well so let's just paste it right up but this is going to be called login the state will be true but we are going to call auth api.login we'll pass in the email we'll pass in the password set state to false show snack bar in case of error but here you can see we are getting a session so we can't use r dot email let's see what properties it has to give us if we do this you can see there are lots of things but none of that will be useful for us except the user ID so let's see if user ID is correct or not so I'm just going to go ahead restart the app oh actually before doing that we have to go to the login view create something similar to what we had done for the sign up view right we can just copy all of this function stuff go to the login View paste it in and then we have on login yeah that's pretty much it now we also need to convert all of this to a stateful widget or consumer stateful widget sorry so we can paste that in import flutter overpod Library import auth controller provider and then call Dot Login now I'll copy this function go down below and add it to ontap and also have the is loading variable just like we had before so if it's loading then we'll have ref dot watch auth controller provider and that's which I'm pretty much it if we do Notifier remember we get the instance of the class we don't want instance of the class we want the Boolean value which is the state value but if you want to do dot Notifier you can do dot Notifier dot state which will give you the exact same thing now I'll copy this as loading put it in the body and if it's loading then I can have constant loader otherwise my widget tree is just fine now I'll restart it and see if it's working so I'll go to the login view I'll first try an email that I haven't registered ravana the rate gmail.com test123 and click on done invalid password password must be at least four eight whatever that is then we'll click on done invalid credentials please check email and password that means it's okay now we can have test at the gmail.com click on done here we have the user ID let's see if it matches by opening the app right console going to test at the rate gmail.com copying the user ID and seeing it over here 5B is there that means it's the same thing that means our login is also working so we completed login very quickly we just have to understand how signup works and log in with very simple so the now the next thing is whenever the user logs in we have to navigate them to the home screen so we can close all the folders in the features create another feature called home create a new folder called View and create the first view which is the home view dot dot file we'll import material dot import a stateless consumer widget called home View import flutter riverpod Library put in a scaffold and see what we get so we can go to the auth control layer so whenever we log in actually let's come here whenever the user signs up we cannot directly send them to the home screen because if we do that and when we try to persist the state the state won't be persisted because State persistence will be done by something like this account dot get is not equal to null so whatever we do this account dot get if it's not equal to null then we'll show the sign up screen otherwise the login screen uh the home screen so here we'll have home screen otherwise the login screen but account.get will only have the account when the user creates an email session so we have created an email session over here only then the account dot get has some value in it if we just do dot create account doesn't have any value in it it's just created it in the app right dashboard but account variable doesn't hold any value only after doing email session create the account value account has some value in it so what can we do well after signing up the user what I want to do if it's a success then I'll just push them to login screen dot route so we have login View dot route but in case of failure we are going to show the snack bar and also over here we are going to show a snack bar that account has been created please login the same thing will happen in login view as well whenever the user creates an email session now we have account has some value in it so I'll just say navigator dot push home view dot route so here I'm just going to create static route and just copy all of the material page thing from sign up view so we can copy all of this from here now we can have home view passed in and we're done your will just pass in home view as well now this looks cool so whenever we log in we go back to the home screen so let's try right now we are in the login screen I'll pass in the email and password then click on done and I shift to the home screen but here's the catch but here's the catch if I try to restart the application we are back to the sign up screen that's because in the main.dot file we have decided that the first screen that should show up is the sign up view but what I want to do is if the account is not null then I want to show up the login screen and how can I do that well as I said in the auth API we are going to create current user accounts account.get so we can just have future model dot account which can be null current user account I'll create a missing implementation for it I'll take this and put it at the top now if you're wondering why I haven't used future either I've used future directly that's because we are going to put this in a future provider and future provider can handle the errors for us you'll see that later on but the point is since we are using future provider we have not used future either just keep that in mind for now later on when we add future provider you'll get to know more and for now we are also going to have all of this try and catch block but we'll remove all of this this is not needed the point over here is just having a try and a catch block so we want to return await account dot get and we'll also put asynchronous function here so basically we'll do account.get it will give us the future account which is the model dot account we'll await it and return it if you don't want to await it it's still fine it will still work so you can do this as well because we are returning future account at the end of the day but in case of error we are not going to have any stack Trace so let's remove that in case of any error we are going to return null so we can return null over here and return null here as well that's why this is nullable basically if a count dot get does not have any value that means that the user is not logged in maybe they've just signed up even then it will have no value but this doesn't return unreliable return data type so it will throw an upright exception that the user has not logged in and that's when we will send out null and later on we can just check if current user account is not null if it is not null that means account.get has some value if it has some value we can show them the home view otherwise we can just show them signup View so now we can go to the auth controller I can go at the top remove everything from here and have Future model dot account obviously we need to import that account model so I can have upright models dot dot and import them as model and then we have more Future model dot account current user and we'll return auth API dot current user account not current user current user account and this has to be nullable don't forget that and now we will create future provider with the help of the snippet code that I made you install in the extension steps Riverport Snippets we can just do future provider and then have current user account provider we don't have to mention the type and future provider as well we can remove the async and just have final auth controller since we want to call the auth controller so we have auth controller and you know what will be a ref not watch auth controller provider dot Notifier don't forget the Notifier otherwise it will give you the is loading value right and now you can just do return auth controller Dot current user and since this is of The Future model future account type it will work fine now if you hover over this this is of the type future provider account which is nullable now that we have this done we can go to the main.dot file and in the home we want to use ref now how do I convert stateless widget to something that can give me vegetarf we did that for the stateful widget we just added consumer before it right consume a stateful widget but here we have to use consumer widget not consumer stateless widget so we can have consumer widget we have already imported riverpod because of Provider scope and here we will have widget ref it's not there in the state here because there is no State class here and stateful widget we had State present we had consumer State present but here we have nothing like that so widget ref is provided to us in the build functions parameters now I can just do ref dot watch current user account provider dot when and when there's a data there will be user so we'll do something we'll return based on that then we'll have error and stack Trace so I'll just prefix this with an st and we have to return suppose an error page so we'll have to create an error page and we already have loading so I can use loader but if we use loader in material app it will be a problem why because we don't have scaffold yet it will give you a very ugly solution of loading bar what I want to use instead is a const loading page because we have already added a scaffold to it so it will show up the loader in a nice page we'll also remove the sign up View and let's see what we have to work on we have to create an error page so I can go to the common have error underscore page dot dot also you have to make sure that in common we export loading page we export error page yup and in the error page now I'll import material dot I'll create a stateless widget called error text return a center child text and we need error for that so we can just have final string error and we'll require this through the Constructor this is all basic concept that we have seen earlier since error text is going to be reusable we need this to have a Constructor value and then we can just pass that in error now we also need to create another stateless widget called error page similar to the Loading page we are going to have scaffold body and then pass in the error text over here this is basically a wrapper around error text so that it can be scaffolded now we also need error again so we'll pass that in have required this dot error take this error password in and it's done great now we can come to the main dot dot return the error page over here pass in the error but it's giving us an error that's quite a thing because we want to use two string over here this requires a value of string and this is of the type object now in the data will be our main logic so we want to check if the user account is null or not so if user is not null if the user is not null that means that the user has logged in if the user has logged in we just want to show the home View but if the user has not logged in so we can put else but since we are using return we can just do this return constant sign up view that means that the user has not logged in now if I restart the app we should be landing in on the home View and that's because we had logged in once right app right remembers that and the user account has some value in it if you try to print the user value you'll see that so we can just do print user instance of account is there so we can just pass in the email and we have tested the rate gmail.com so we can remove this now restart the app and state persistence is also completed but we are not done with authentication part yet because whenever the user signs up we just don't want to create a user in the authentication tab we also want to do that in the databases tab in the user's collection that we have to now create so basically we want to save the user data to app right database so let's get started with it right now so we are going to start off by creating a new API here which is the user api.dot file and here similar to the auth API we are going to create an abstract class so we'll have abstract class I user API now why is this different because this will contain all the user API related calls for example we're going to have save user data get user data update user data getting the latest user profile data all of those stuff those are very different from auth API because even if there is no authentication and somehow we need to store the user data this will be handy it is independent from the auth API that's the whole concept if you don't want anything just delete it and it shouldn't cause problems in any files or it should be less work to do in some other file now in this case we are going to have this so our first thing is future either void save user data and we are going to have this then we are going to create the user API which is going to implement I user API and now we can create its implementation but before creating the implementation we have the save user data but what user data do I have to save I'm not getting that so I want to get it from the parameters here but manually getting required string email password all of that stuff what I can do instead is create a model for this so I can just go to the lib folder create a new folder now called models and have the first model which is a user model creator now this user model is going to have a bunch of properties and this user model is exactly what we are going to store in app right as well so let's note down all of the properties that might be required in this user model first is the email then is the name we are not going to store the user's password in this database because it's not going to be encrypted over here we want the user's password to be encrypted all the time so I'm not saving password here then we need other things and let's write down all the things that we require we'll require a list of string of followers why is it a list of string of followers because we are going to store the followers in the form of their uids uids is the user's unique ID that we saved earlier and we saw earlier in the upright console as well so we're going to store that as the followers so we'll be able to get the list length and all of those stuff with this and another thing we need is following similar to the followers one it's going to contain a list of uids of the user following then we are going to have a final string of profile picture so what is the profile picture going to look like then we also have the banner picture right that will show up in the user profile just above the profile picture then we need to store the uid of the user then we have the bio of the user bio is the description and finally we have a Boolean of is Twitter blue so if they've subscribed to Twitter blue or not so this will decide if they should have a blue tick mark Or Not beside the name and now I want to create a Constructor a two map from map functions for this so I can just click over here and create a data class generate data class how am I getting this option if you go to the extensions Tab and type dot data class generator you'll get the extension on this so install them or install one of them and just click over here and generate a data class and it will generate it correctly for you now we can remove dot convert let's remove this go down remove the from Json to Json function we don't need that because we are not making API calls we already have upright API we are going to use that upright client to save data to database so we don't need to encode and decode and all of the do all of that stuff in the two map now let's go through the functions that it creates first is the Constructor and since all of the fields are final I can put this as a constant and mark the class as immutable so it creates a Constructor where every field is required that's good now we want to copy with now we have the copy with function this copy with function will be used whenever we want to copy the class Fields with another field so example we have some user model and that user model is something like this so user model user is equal to user model and there are a bunch of fields like name is present like Revan and all of those stuff right now I want to update the name of the user so I can just do user dot copy with ignore the case sensitivity and then I can just do name as a new name so I can just have driven like this so what's happening over here is basically all the other fields remain the same but but the name we are trying to change can be changed to this function we need copy with function because all of the fields over here are final if they're final that means they are immutable the values cannot be changed once they are made so I cannot do user dot name is equal to Revan like this it will give an error and that's why we need this copy with function then we have two map function basically whenever we have user model created and we call user.2 map it will convert all the fields into a map format we have a map over here and we just do result Dot add-all and it will add email email name name like this then we have from map now in two map there's one change to be made we have to remove this field because we don't have to store the uid of the user on app right because app right automatically creates a unique ID for us so we don't have to create another one we can just have it present in from map and in from map we are basically getting the map and we're converting it into a model and over here you see we have map at uid but we don't have any field like map at uid over here right we have removed the call because app right automatically creates the ID so to fix that I can just have slash dollar ID why because when apprite automatically creates the ID it is stored with the name as dollar ID and if we just do dollar ID you can see it gives us an error it thinks this is a variable which is trying to get stored and there is no variable named ID but if we put slash it will get to know that we need to ignore this string interpolation and just use dollar ID over here basically this will retrieve the automatically generated ID app right gives us and we're going to do this for literally every user model that we create and then we have the tostring function so while debugging if you want to check the user model if we put usermodel.2 string it will give us in the print command in the terminal something like instance of user model but I want to get to see what user model is there What fields are there so I can just overwrite the tostring method so that I can show everything else and then we have the identity property so basically we won't be using this at all in our application so you can remove this but basically what it does is check if two user models are the same thing or not and it does this by checking each and every field and seeing if their properties are equal or not so this was a user model now in save user data function I'm going to have this user model created now I can create one missing override for this and now to create something in database we always have to have a try and on app right exception catch block with E and F T catch e s t we have already looked at all of this before and now how do I create app writes now how do I create a new document in app rights database so to do that I have to import something known as databases which is a private variable DB now I'm just going to have user API required databases DB and set underscore DB equal to DB right now I can take this underscore DB put it in the try block and have DB Dot create document you can see it's very intuitive we want to create a document it gives us a create document function now we need to pass in the database ID do we have the database ID stored in upright constants yep we do so we can just have app right constants dot database ID now collection ID collection ID can be users right no this is not how apprite works it shouldn't have collection ID as the name of the collection there is a collection ID given to it so for that we'll have to go to the database we are in click on create a collection and pass in users now I can click on create copy The Collection ID go to Upright constants and create static constant string users collection equal to this thing right here so I can come to the user API just pass in upright constants Dot users collection then we want to pass in the document ID which can be ID dot uni right we don't know the document ID and this document ID is also going to be the ID of the user now finally we need to pass in data and data is user model dot to map we had created two map function in the user model and that's what we are using now we can await this store it so we have final document is equal to this we can also put async over here and then return write null so everything goes fine yep we don't have to return anything so we can also remove this final document equal to because we don't have to store it in case of failure though we have to return left failure will pass an e Dot message otherwise some unexpected error occurred and stack Trace will be St we can put the same thing for the catch block as well but your e.2 string and this part is not required great now save user data function is also created let's create a provider for this I'll let you try this on your own pause the video and try it on your own so that you start developing the confidence to do it on your own if you're able to do it great we just have to create a provider like user API provider then we can have provider and we'll return this user API class now we need to pass in the database to get the database of course we'll have to create a new provider in providers.dot which is final app right database provider we created one for account we created one for client now it's the time for database so if you get confused on when to create provider if I have to create a provider or not you just have to ask yourself is this a dependency if it's a dependency you have to create a provider as it will help you in testing so yeah upright databases is a new dependency and that's why it's being stored over here we are not creating an instance for this we are directly injecting this in our class so here we can just have return databases now we need to pass in the client so we can get the client like this pass in the client and we are done and in the DB we'll pass in ref.watch app right database provider that's it user API is now created now I have to go to the auth controller import the user API here so we have user API underscore user API we'll require this so we'll have required user API user API and then we'll have underscore user API equal to user API just what you have done before here it gives us an error because user API is required what do you think will come here exactly where F dot watch user API provider now we can scroll down and let's think what we want to do whenever the user signs up we want to store the data in the database but when the user logs in do we want to store the data no because the user just has to log in he has no data that we have to store we have already stored that in the sign up process so we just have to do it over here so what we'll do is create a user model here I said user model is not going to be created in user API or any of the conversions are not going to take place it's purely for app right so that's why we are creating the user model here so user model user model is equal to user model now we'll pass in the email now we have to get the name the name in the sign up process is going to be extracted from the email only so we can go to the utilities dot dot create a function that will return to us a string of get name from email we'll pass in the name and now we'll just do return actually we'll get an email here right we'll get email and we'll just do email dot split by at the rate and take the first element of the list basically what we are trying to do is if I get Revan gmail.com I'm just going to split this email by at the rate so we'll get a list which is something like this it will have rivan ranavat first and at the rate gmail.com as the second element so after we get this list by doing split by add the rate we'll take the first element which is because that's the name of the user right so we get the first element and we return that so we get a string now I can just put your get name from email pass in the email followers in the initial part are going to be empty list even following is going to be empty list profile picture is going to be empty Banner pick is going to be empty uid is going to be empty because it doesn't really matter because you're not doing Dot 2 map uid we have removed two map uid property bio is also going to be empty and is Twitter blue false obviously when the user signs up why will we give them Twitter blue and of course we'll put both of them as constants now I can take this user model and pass it to user API dot save user data pass in the user model now let's see what we get we get future either and all of those stuff so I can just have final res is equal to await save user data but we're getting this error because this function is not asynchronous so make this function asynchronous we get result now we can again do result.fold but not to get confused with the previous result we can name this final result 2 and we can do result 2.4 if it's a failure then we want to show a snack bar with l dot message and if it's a success we can copy this go to the right value and paste this end R doesn't return to us anything so we can mark this as underscore but basically what we did was created a user model so that we could store all of this data in the database then we can have user API dot save user data which saves it to upright and then we check if it's a failure if there any error occurred if any error occurred show that in a snack bar otherwise we can just go to the login view and say that the account has been created try to log in easy now we can restart the entire app and it will work now this is the beauty of separating your code into separate layers you see we don't have to go to the view file at all we had all the work related to the database and user creation user model creation all of that was done between controller and repository we didn't even have to touch the UI file this is what makes the code more robust if you have a work in certain file you only do that in one file it doesn't affect other files at all now understanding this let's try to restart we are still on the home screen because you have put the logic like that and we don't have a sign out button as of now so let's try to ignore this logic as of now we'll put this back in but just so that we need signup view so that we can see the data is being stored or not we can create a user so I can just have test one two three at the rate gmail.com test one two three four click on done and you can see the current user is not authorized to perform the action now that's because we have to make some configurations in upright console as well in settings you have to go down and you see update permissions you have to add a role so that someone can create a user update a user or anything so I'll click on add a role any and anyone can create a user and I'll update that I'm not giving them read update or delete properties why is that because when the user is not a user you can see the role has all users all guests select users when the user is not really a user that means that the user has not logged in or signed up or anything they can just create a user so that you know we can put that in the document right now the user is a guest right now the user is anyone it's not really a user so he can create the user document but he cannot read update or delete that would be a wastage of calls they can just create so this allows us to restrict certain people from using certain features of our application now if I try to do done a user with same email already exists so we can have one two three four click on done and you can see invalid document structure unknown attribute that means the role part is now completed we are getting a different error message and that's because in the attributes we need to add all the attributes a user can have that means all the properties a user document has so in the create attribute we have to pass in basically everything that's mentioned in the user model except uid so basically everything that's mentioned in Tuma so let's pass in and create those attributes so the first attribute is email which is of the type string the size you can mention which is a required field I'll just pass in 255 and put it as required so this is the email attribute now we need the name attribute so I'll pass in the name c string 255 is the size I'll click on Create and I'll do that for all of the fields for example for followers I can pass in followers which will be an attribute type of string size will be 255 or you can just extend this because a user can have more than 255 followers let's just put thousand ten thousand anything I'll put thousand and I'll say that this is not required this is an array then click on create I create another attribute for following so I'll copy this paste it here click on string array create the next attribute is profile picture which is a string so I'll have string but this is not an array this is a required field so the size can be 255 or 1000 again because the URL can be long but since we are going to store the profile pic in apprite storage itself the link value will not exceed 255. so we can just put that then we need the banner picture as well so I'll pass it in string and require that's it then I have bio I'll pass in the bio which will be a string but the size can be a longer than 255. so we can put thousand as the value and last thing we have is Twitter blue so if it's Twitter blue the value is Boolean the default value it is a required value so we don't have to pass in a default value and then we can click on Create and now all the attributes are there all of the attributes need to be mentioned before you make the call to the database for the user's collection later on we'll have tweets and notifications collection even that time you'll have to manually add all of these attributes now this attribute feature is quite good because in case you roll out your app to certain users and later on you decide that you want to have more attributes in your application for example you are try to add one more field like a link attribute to the user so you can add link select string and just click on create and it will add it to the attributes now this is helpful because it will also add the link attribute to the already existing user documents this is an improvement over Firebase Firebase doesn't allow all of this Firebase gives us a merge property but it's very hidden in the docs many people don't know about it with this attributes feature it's quite good because it will add it to all the documents all the users present in your application so there's less possibility of your app breaking anyways now that we have this done let's minimize this and click on done user with email exists so we can have one two three four five click on done account created so I'll just try to refresh and here it is test12345 and name is test one two three four five this function which is present in the utils OR dot get name from email works fine for us because it's given us the correct name so we have followers following profile pic Banner bio and if it's Twitter blue it gives us a check mark so we can set it to true or false pretty neat now I'll try to log in from this same users account so we have test one two three four five at the rate gmail.com test one two three four five click on done Actually the password is just test one two three four and now I'll add this logic again restart the app and we are still on the home screen now our entire authentication process is completed of course let's just change this to Twitter clone now too late for this but let's change it and now what I want to do is run the same app on Android emulator I know many of you might be coming to this time stamp right now I'm just going to run Android emulator and show how to fix the problem you'll face while using Android emulator so I do not do this before it just skipped out of my mind so let's do this I'll close this iOS emulator for now run the Android emulator and I'll see you when the app loads so our app has started on the Android emulator if you see here it tells you to upgrade the compile SDK version which is just a warning but might not work later on so you can go to build.gradle Android app in the compile SDK version you just have to change this to 33 and the error will go away now another thing is if we restart the app you can see upright exception null config connection refused and this error occurs because Android emulator doesn't know what localhost is so if you just go to app right constants you can see it doesn't know that localhost is there and is unable to get resources from there so to fix that you can come here and change it to your IP address so you have to pass in your IP address like this so if your IP address is like 191.2.3.4 you know anything like that just put it here and it should work another solution is just to type in the command ADB reverse TCP colon 80 TCP colon 80 and after you press enter it should fix the error for you I'm more comfortable putting my IP address so I'm just going to put it here and see you after I put it and restart the app after you followed either of those steps let's restart the application and you can see apprite exception General unauthorized scope user rule guess missing scope account and now we are getting this error the reason for this error is basically if we go to the auth underscore API and see this here actually we don't need the catch so let's remove that and another thing that you might notice is when we do current user account we do need to put a weight earlier I said that you cannot put a weight and if it's it's fine if you don't put a weight but it's actually needed because you need to avoid it so that you get the account and then you want to return that account doing this and this is not the same thing so after you do this restart the app and here you can see this works fine now so if you got this error that was my mistake I said you cannot put this but you should put this anyways now that our app is working you know let's try and create a user so I'm just going to call this username under one at the rate gmail.com test1234 click on done account has been created so let's login so we have test one two three four again and click on done and now we are signed in everything seems to be working if I restart the app this works now so there were two changes to be made one is this one return await account dot get not just return account.get and other thing was apprite constants either using the terminal ADB command I'll mention it in the description below or you can just use your IP address and put that in now that you have both of these things done and our app is working on Android and iOS as expected the next thing we can do is design the home screen with bottom navigation bar down below a feed screen a search screen and the notification screen so let's get started with the bottom app bar and see what other things that are needed there so for this we will go to the lib folder and again in the home view we are going to create our scaffold now what all things are required we need an app bar and the app bar is going to be the same app bar that we have in UI constants so we are just going to use this and even before doing all of this there's one thing we have to convert all of this into a stateful widget so we have home view here now we need to return a scaffold here as well as take the route from home view consumer widget and put it in home view stateful widget now we can remove this we have done this because we need access to set State because we are going to have a bottom navigation barrier and whenever a icon on bottom navigation bar is clicked on we need to change the page that is being displayed so now again we are going to have final F Bar is equal to UI constants dot Abba now we can take this app bar and put it right here next thing is a body but we'll figure out body later on but before that we need bottom navigation bar and bottom navigation bar is Cupertino bar now we have that you can also use Cupertino you can also use bottom navigation bar not just Cupertino tab bar I just preferred this style of Cupertino tab bar now I need items an item will be a list of bottom navigation bar item so I can just have bottom navigation bar item pass in the icon and icon is going to be SVG picture dot asset and pass in assets constants dot home fill icon correct now if I want to see this on the screen we are getting this error so let's restart the application and we are getting another error the reason for that is there are not two bottom navigation bar items which is the bare minimum so I can just put another one and this one is going to be search icon now I can save it and here we have it this looks good but there are many changes to be made for example the color of this bottom navigation bar item should change we can do that over here by having active color and active color but since these icons are SVG picture asset we can pass that color here so we can have palette dot white color and the same thing can be passed in over here now this looks good the third bottom navigation bar item that we need is notification icon so we have notification filled icon and we can pass that in okay now we also need to change the color of this so that it matches with our scaffold color so we can have background color AS Palette dot background color you can also change this in the theme of the application foreign so you can go to the app Theme and add this it works either way and now this looks good now we want this toggle to happen and based on the toggle we want to show the icon so if we are on the search icon we don't want to show the home filled icon and notification fill like and we want to show their outline the icon so to make that happen we are going to have int underscore page equal to 0 and this is going to contain the page index we are going to be on so I can copy this and pass this as the current index of the Cupertino tab bar and on tap I can have a function created which is void on tap on page change let's call it that this will give us some index which will be the index the user clicked on and then we can set state so that the build function rebuilds and have underscore page equal to index now I'll take this and pass it in I can directly pass this in because the function signature that ontap requires function integer and parameters is exactly what void on page change is and now based on this page I want to show the item so if we are on page 0 then I want to show filled icon otherwise I want to show assets constants dot home i o line icon the similar logic will go over here so if you are on page one then we want search icon otherwise it's normal search icon because search icon is not bolded but this logic will come over here as well fifth page is 2 we want notification field icon otherwise assets constant dot notification outline icon now we can paste this in and this works you see this this is an outline now if I click over here this is not this is outline not filled and this is also outline if I click over here this is filled and both of them are outlined so that means this is working now we want to display the appropriate body so in to display the appropriate body we are just going to have body and password index stack where are we using index stack instead of a page view or another widget like that that's because index stack helps us maintain the state so example if some tweets are shown here and we scroll down and then we decide to go to the search screen so that we can search something and come back this will not rebuild the entire widget this will keep its state maintained and will be on the same screen or the same tweet we were earlier watching so it maintains the state you'll see that in action when we get to that part I'll highlight it to you but for now this is what it does so now the index is the page and children we have to pass in a list of bottom top bar pages so I can go to the UI constant so that I can create this constant and create static widget actually list of widget and call this bottom tab bar pages and this will be equal to let's say the first one is a text widget and the text widget is going to say feed screen because we should see feed screen over here feed screen is basically a screen that shows us the latest tweets then the next screen is the search screen and the third one is the notification screen now I can come here and have UI constants dot bottom tab bar Pages restart the entire app and here we have it feed screen is showing up if I go your search and notification screen now the last thing we need on home View widget is a board a floating action button so we can have floating action button and in the on press right now we are having nothing but basically it will navigate us to the create tweet screen and in the child I'm going to have constant I can ikins dot add now if I do this much you can see we're getting this this blue color is because in the app team we have specified The Floating Action button theme to be palette dot blue color exactly like Twitter but we want the color to be changed so I can just pass in your the color AS Palette dot white color this looks good another thing that I need is its font size to be increased so I can increase its size by let's say 28 and this looks good now what I want is whenever I click over here it should open a create tweet screen so I'm going to close the home feature as well create a new feature here called tweet and this is going to contain all the Tweet related features like create tweet screen tweet list which is basically the feed screen all the repository for all the controller files related to it and of course the repository or the API files are going to be mentioned here so coming back to the Tweet we want views and in the views we are going to have create tweet view dot dot so I'll import material Dot and then we are also going to import flutter riverpod package and after that we are going to use the stateful consumer widget and call create tweet screen this consumer stateful widget snippet is provided to us by flutter airport Snippets extension on vs code this is a stateful widget because we are going to have a text editing controller we are going to have the ability to share images so we need all of this so now let's start by designing this screen so we have scaffold and let's see how we want the create tweet view to look like so this is what we are trying to build we have a close button here we have our small rounded button here then we have this long text field and a bottom bar beneath also here we have some space for our profile picture which is right now empty but if there is no picture then we want to show some default picture so let's start designing it the first thing we need is an app bar and in the app bar the leading icon is icon button where onpressed is required and icon is required and icon is icons Dot close and the size should be bigger than normal so we'll pass in the size as 30. we're not really getting anything because we have to click on this and to go to the create tweet screen so first of all let's create a route for this so we can go to the home View copy this route line paste it over here and pass in create tweet screen you can also name this create tweet view whatever you like then in the home view you should have on create tweet so whenever the oncreate Tweet button is clicked so we just want to do Navigator dot push and we need to go to the create tweet screen dot route now we can copy this and paste it in the on press offloading action button let's restart the application and if we click over here we have the button showing up that's good now I need the Tweet button to show up so I'll just pass in the actions property to the app bar and I've rounded small button where on tap is going to be empty and label is going to be tweet I'll save it and you can see this button shows up but I want the color to be blue and the font to be white so to do that I'm going to have background color property which is not a required field remember and then we can pass in palette dot blue color if we save this much it looks good now we just need to change the font color so the font color or the text color is palette dot white color and there we have it looks good now in the body let's get out of the app bar and in the body we are going to have safe area widget and then pass in a child the child is going to be single child scroll View and in that we'll pass in a child of column path and children and the first child that I want is a row to make you understand why we need column is basically we have this entire thing so this is in a row format the profile picture and the text field but this line is also included right this line is below this row that's why we need a column so that we can place this divider in but even before that we need a row so we'll pass in a row as children and the first child is circle Avatar we'll pass in the background image and background image will be Network image and network image the image that we want to show here is basically the user's own profile picture so to get that we have already created a provider for that which is final user which is equal to ref.watch now to get the user data we'll have to go to the user API and create a new function for it so we load to the user API and create a function called future document now we have called this future document not future either document is because we are going to use this in the future provider so that it becomes easier for us to get and display the data so we can have get user data and then pass in the uid so we need the uid of the user and based on that we can get the user data this get user data data is basically the data that's stored over here in the database it's not the authentication data we have already created a provider for that which is get user account data provider or something like that now we need to get the database data right so now let's import document so for document we are going to have model dot document and we'll import app right with models.dot and obviously import this as model so we have modeled our document now I can create one missing override I can copy this function for the try and catch block actually we don't need the try and catch block future provider will do that for us in case of any error it will give that to us so now I just want to return DB dot get document we need to get one particular document right to get one particular document we have to pass in the document ID and we are very sure that this user is only going to have one document because they have a particular uid and this uid is automatically generated and is only present once in the upright dashboard so I can just pass that in as the document ID confidently and for the database ID we have upright constants dot database ID and collection IDs upright constants Dot users collection so it will give us the document you can see that document and it has the correct collection ID and the document ID which is the uid of the user now I can go to the auth controller because that's where we are going to need it later on and we are going to create a function called future user model so whatever data we get here the get user data function it's going to return a document now we need to convert this document in the form of a user model I said all the model conversions should take place in the controller not in the user API so that's why we are creating this function over here and we have get user data string uid async and we have final document is equal to await underscore user API dot get user data and we'll pass in the uid we are basically calling this get user data function that was defined in the user API class now we can just have final updated user is equal to user model Dot from map and pass in document but this is document I want it in the form of a map right so I can just see if it has anything and yep there's data so you can just have dot data passed in which is in the map format and it will give you the output now I can just return this updated user again we've not put try catch here because now we are going to use this in the future provider so we are going to have future provider user details provider it's not going to be asynchronous it's just going to have auth controller and then we are going to return auth controller Dot get user data now to get data we don't know what is the uid of the user right now because this is just user details provider not current user data is provider basically this future provider will be used even in future when we want to view the user's profile suppose that some other user I'm user number a there's user number B showing up when we search up the user or we click on the profile of a user when the Tweet is shown we want to be able to see their profile right this is when get user data is going to help us this is a reusable provider so I want the uid to come from the UI file so to do that I'm just going to have dot family after this future provider and now I can have string uid taken from here now whenever I call this user details provider I need to pass in this uid like a function I'll show you a demo right now we are going to create another future provider called current user details provider this is for the current user this is the provider we are looking for in the create tweet view this provider is going to be used inside of this provider so now I can I'll not have family over here I'll just remove the async call I'll have final user details which is equal to ref dot watch current user details provider I'll pass in the uid and to get the uid of the user not current user sorry we want user details provider don't get confused and here you can see it looks for a uid and we need to treat this as a function when we use family now I want to get the current user's uid to get that we can do final current user ID is equal to ref dot watch current user account provider which is this account as I said this account only exposes one useful API for us which is the uid so we can access that by doing Dot as data now we have to do all of this because this is of the type future provider when we hover over this this is giving us async value of account so to remove async value from Earth and get the value of account we need to do dot value and this cannot be null because it's a current user ID it cannot be null Dot ID which is dollar ID and that's why in our user model if you see we had passed in this because dollar ID is basically what the value of this account is dollar ID now I can pass this current user ID over here and return user details dot value now we'll go to the create tweet View and in the build function we are going to have current user which is equal to ref dot watch current user details provider Dot value again we cannot do just this much because current user is again async value because current user details provider is also a future provider and we just now saw how to handle the value of a future provider which was the current user account provider this might get a bit tricky so try to understand the code and move forward or you can just rewind the video and watch it again so now that we have current user with us we can get its value and then check if the current user is null or not so if the current user is null then we want to show a loader so we'll have constant loader otherwise the safe area widget and your background image is going to be current user Dot profile path and now we're getting this loading indicator the reason for this loading indicator is because we have made a big bug in our application that's because if we go back to our auth controller you'll see that the uid is empty I told you that uid is not being used in two map but when we try to save the user data the ID should not be unique it should be the same as the account ID so right now if you see I tried to print the current uid of the user account and the same account in the database is having a different ID they both shouldn't have the different ID the reason for that quite simple because when we try to retrieve the user ID we are passing in the account ID that's the only account ID that we have access to we have nothing else to get data and that's why both of them should not be different so to correct the changes what I'm going to do is in the uid I'm going to pass R which is account dot ID and then in the save user data function the document ID is not going to be anything unique it's going to be user model Dot uid so that was a mistake I made now I'm going to erase everything all the data from the database and even the auth console so that we can have a fresh start and see if you're not making any other errors or not I'll see you when I stop finishing the delete process so I've deleted everything now let's try to sign up the user so we have test at the rate gmail.com I can reuse this because we don't have any user now and then test one two three four the user has been created test one two three four other gmail.com test one two three four done I put in the valid invalid I just have to get done and here we are now I'll just restart the app go to the screen and there is no error except this so that means everything else is working fine now I'll explain this error to you but before that let me just remove the print statement that I had put for my own debugging if you want to make sure you can check that the ID in the user's collection right now and the ID in the app right auth console is the exact same thing please do not forget that and now talking about this error we got this error because our Banner pick is empty and still we are trying to show that so it's not able to show an empty URL image right so to fix that what I'm going to do is temporarily just add a profile Pickaway by searching for one over here so I've copied an image address I pasted it over here clicked on update and now if I try to refresh the application go back to the create tweet screen our image now shows up that's pretty good now after resolving all of these bugs which I apologize for if it's not clear why we did what we did please let me know in the comment section it's an important concept now in the circle Avatar I'm just going to put a radius and the radius is going to be 30. so here we have this image now I'm going to leave some space so size box but this time a width of let's say 15. and then we are going to have a text field and in that text field I want to pass in a controller which is going to be tweet controller so we have final tweet text controller we are naming this tweet text controller not tweet controller because tweet controller is going to be the name of the controller we create for tweet over here tweet text controller is the text editing controller now I can take this dispose It Off and pass that tweet text controller over here now I want the style so we have constant textile of font size 22 and the decoration of constant input decoration where we mentioned hint text which is what's happening right now we are not able to see the text so what I'm going to do is pass in a hint style and the hint style is going to be textile with a color of palette dot gray color and we weren't able to see it in fact because the text field and circle Avatar are in a row and text field has a tendency of occupying all the maximum width it can get but since it's in a row and circle Avatar is also there it's not getting the maximum space therefore we are getting this error so to resolve this I can just wrap this widget with an expanded widget after I do this you can see we are getting this expanded gives us the maximum available space in the screen so expanded get gets all the remaining space now I also want to increase the font size to let's say 22 and the font weight so that it looks a bit bolded as font weight dot w 600. and this is looking good now the last thing I want to do is basically give it n number of lines and also remove this border so to remove the Border this is going to be quite simple border is input border dot none we don't want any border and then we want Max lines to be null because if we don't do this you can see I'll try to type I'll try to type and it keeps on moving in the horizontal Direction when I overflow this line basically I want to go to the next line so to do that I'm going to pass Max lines which is outside this decoration Max lines as null once we pass in null it gets unlimited lines so if I try to do anything you can see I have n number of lines so this is it now at last what I want is a divider to be there so that I can start showing my bottom navigation bar which contains a list of icons so if you want to add image you can add image Emoji Emoji gifgf so in the bottom navigation bar we are going to have bottom navigation bar and this is not necessarily going to be a bottom navigation bar in fact it's going to be a row where we'll pass in the children the first child is SVG picture Dot asset and I'll pass in assets constants dot gallery icon and now if we see over here there is an icon we can see that but there is one problem and that's because we haven't added any padding so to add a padding we are going to wrap this with a padding widget so that it has eight now this looks good but other thing that I want is this to be padded from the left and right direction so I want it to be having padding of eight from all the sides and copy with I want left padding 15 and right padding 50. so from all the sides it's 8 except left and right left and right is 15. so we have the icon showing up here and we want left and right because we are going to have other two icons which are also going to be left and right 15. so that's going to be GIF icon and there's going to be emoji icon all of this mentioned in assets constant and here there is look great but now what I want is a line to be present over here so to put a line I can do two things I can pass in the column a divider right here but other thing I can do is wrap this row with a widget known as container and this container will give us decoration of constant box decoration border and Border should be border from the top as Border Side and pass in the color which is palette dot gray color and now if we see here is the Border but it's quite thick so I want it to reduce the width so it will be 0.3 and this looks decent enough last thing I want is it to have a margin From Below so what I can do is add a padding property of constant Edge in such Dot only from bottom 10. now save it and here we have it the icons are raised from the Bottom by 10. now all of them are visible the next thing is now whenever I click on this this should pop off the screen should pop off and whenever I click over here I should get the ability to add images so now what I can do is just have navigator.pop so that it pops off the screen and goes to the home screen so if I click over here I'm back to the home screen if I come back you're back over here now whenever I click over here I want to pick images so to do that we are going to add a plugin known as image picker and then it will give us a list of images we can select from and we will get the images over here displaying in the form of Carousel and then we should be able to tweet that so this is the plugin we'll be using for image picking image picker plugin so I'll just add that dependency and another dependency that we need is Carousel slider I'll install both of them together basically Carousel slider will help us with displaying the images in a carousel format and image picker as the name suggests is in image picking now there are certain installation steps to be required for iOS if you're on Android you can skip through this part for iOS what we need to do is add this key to n4.pls files so let's go to iOS slash Runner and add the info.plist and add this key sorry so there are two keys NS photo library usage description and NS camera usage description you can also add the third key which is the NF microphone but you won't be needing this because this isn't related to camera this is for video recording and you also need to mention the description of this but since I'm not uploading this to App Store I don't want to waste time writing something and making something up but if you're deploying on placed app store it's very important otherwise your app will get rejected anyways coming back to this I think the whole process of installation is done I can restart it on Android nothing else is required the compile SDK version should be 33 and we've already changed that to version 33. and while that is happening let's go to utils.dot we'll close all the other files and here we are going to create a function for future list file so that we can pick an image so we have pick images function we are also going to create a separate function for picking one single image and this will be required when we'll be using profile picture and banner image we just want one image that time but right now we can pick multiple images so you'll get a knowledge of having both you can either pick one single image or multiple images now here to pick multiple images what we need is a list of file we'll call this images and will be an empty list for now and then we'll instantiate the image picker plugin which is equal to image pickup now I'll take this picker pick images and you can see we have option to pick image and pick Multi Image we're going to go ahead with pick Multi Image and save this to a final variable called image files and now we'll check if image files is not equal to null and it's never equal to null so you want to check if image files dot is not and actually we need to await this before we can do anything else and now we want to check if image files is not empty then what we need to do is for final image in image files so we are running a foreign Loop basically we'll go through the image files and we'll get an element from this list called image and we'll add that to our images list that we created over here so we can have images dot add file image dot path so this is in an X-File format we basically get its path convert it into a file and add it to the images and now we can just return this images so this is the entire pick images function now I'm going to go ahead and bind this to our create tweet screen so I'll scroll down and find the bottom navigation bar item the gallery icon I'm just going to wrap the SVG picture with a gesture detector so we have gesture detector and we'll pass in the on Tab and just to mention this gesture detector is wrapped over here instead of the padding because if we wrap it over the padding whenever we click over here not on the icon over here it will still get selected I don't want that I only want it to get selected when I click on this icon that's why I've wrapped it around SVG picture not the padding and now on the top I'm just going to create an image of function for it so we have void on pick images and here we are going to call our pick images function from util.dot file this is going to be asynchronous we'll await this and then we are going to have a global variable basically we want to be able to show these images live on the screen to show them on the screen we are going to have list of file images which is equal to an empty list and now I want to import dot IO and now what I want to do is set images equal to await this and set state I'm not doing such State you know like this because I'll have to make such State asynchronous function instead of doing that I'm just doing this above such State and then calling such state so that the build function rebuilds and then I'll be able to show an image so to show an image actually let's just link this on pick images function right here and see if we are able to select images so if I click over here select photos I'll select this image this image and this image click on done and I think it should show up so now what I want to do is if the image list is not empty initially it's empty if the user doesn't select anything it's empty if it's not empty then I want to display the carousel over here that's why we have added the carousel as well so now what I want to do is in the column we are going to have if images dot is not empty so if the image is not empty I want Carousel slider to be present and what are the items of this Corrado carousel images right but this items requires a list of widgets so we need to map this why do value mapping image because the items are based on images and we will map each image so that we can return a network image not really a network image image dot file the reason for that is here we have selected images from our memory created that in the file format and now we want to display them in the file format so now instead of e we can name this file and pass in file to this over here and so that the error goes away we can convert this to a list next thing I need is options and option is going to be carousel options height 400 and enable infinite scroll false so you cannot continuously keep scrolling and finitely like even if the last image gets over the first image will show up after that we don't want that if this is the last image we won't be able to scroll further so we have image.file return but there are some modifications to be made so let's convert this in a block and we'll return image.file from here and have this now let's just see what we have till now so I'll just select an image here we have a list of images they look good but there are certain modifications to be made for example we want them to occupy the entire screen with we want them to have a margin from the side so we can wrap this with a container Widget the width will be media query dot of context dot size dot with media query width is basically the entire screen width and then we need the margin and the margin is constant Edge insets dot symmetric horizontal 5. so we are having a margin of 5 from left and the right side so that the images don't stick together and this looks pretty neat so we have the Carousel and this looks good we are not going to add any more thing over here this can be more beautified later on but you can do that by yourself the main point now is whenever we click on the Tweet option we should be able to tweet depending on if the image is present not present if the text is present not present anything so to do that we'll have to do multiple things let's close all of the features here in the Tweet we'll need a controller which will be tweet controller.dot and even here we'll need something like a tweet API but first let's figure out how the Tweet controller will work I'll explain it to you how the Tweet controller will work we'll write the boilerplate code for tweet controller and then we'll get to the Tweet API which is a very simple function but we have to write all the boilerplate code over there as well so let's get into it so let's create the basic state Notifier and state Notifier provider so we have state Notifier so this creates the whole code for us now we can just type tweet controller remove the nodifier from here so let's remove this and we have state node file now what is the type going to be well it's going to be Boolean again nothing different and this is going to be false we have a lot to import over here but we'll import that later now what I want to show over here is basically what are the functions that we are going to have over here now the first function we are going to have is share tweet function pretty simple and you might think that this is the only function that's required but no controller is doing the heavy lifting here tweet API is also going to have just one function the shared tweet function it's just going to receive a tweet model that we are going to create in function and based on that it will be able to convert it to map and upload it to Upright that's all uh tweet API will do but in our case the Tweet controller is going to do a lot of tasks first it has to determine whether the Tweet has an image or it's just text and it will also determine other things like hashtags link so that we can display them appropriately so this is a shared tweet function it's going to require many things so let's require them first thing that's required is a list of file of images we will check here if the images are empty if the image is empty that means we are sharing only a text based tweet otherwise it's an image based to it so we are also going to require text is always needed we also require build context so that if K is of any error we can just display them we also need I think for now this is all that's needed when we come to the reply section we are going to need much more than this now inside of this as I said we are going to have some functions for example first we have to check if text is empty so if text is empty we will not be able to move forward we can just say show snack bar please enter text so the user should be able to enter text and then we'll return from the function then we'll check if images dot is not empty so the images file or the images list is not empty then we want to share a function or we want to create a function called share image to it and here we are again going to require many things so let's just copy these two paste it in here and when we come to the reply section again we'll need many stuff I also forgot the build context so let's put build context here and then we can call share image tweet and we'll pass in images text and build context now if the image is not empty or the images dot is not empty is false that means that the image is empty then we want to share a text based tweet so we can just create another function called share text to be and we can paste that in similar to the share image tweet so we have shared text to it but this time we will not have images here because it should take space to it why do we need images now notice that we have made both of these functions private this is because they shouldn't be used outside of the controller only share tweet should be pushed outside of the controller that's because we want to do heavy lifting in controller we don't want to expose all of this logic like share image to it is if images is not empty if image is empty all of that we don't want in the UI file let the UI file be clean we want the controller to be present and controller can do all the weird tasks that are there right now either it is image tweet or text-based tweet we want two things to happen we want to get hashtags from a text and we want to get links from a text so we'll create the functions right now so we have the first function which is string get link from text so we have a text over here and we want to get link based on it so now first of all we are going to get the words in the sentences so we have list of string words in sentence which is equal to text Dot split so we are finding the words and putting them in a list format so suppose the sentence is YouTube okay so it will convert this in a list format like this Revan of course with a string like a inverted comma like this but just for demonstration rewind on our YouTube okay so we have this inwards in sentences now what I want to do is check that if each word starts with https or www dot so I'll just do four just like we did earlier string word in words and sentences and then check if word dot starts with https colon slash slash or word dot starts with www dot then it's a link right so none of these are links but if I add h w w dotanawat.com or www.youtube.com slash it identifies it because we got this word in the list it looped through it and checked yeah it starts with www dot correct so now we can just say link is equal to word and where is the link well I can just create a link variable right yeah and then we can return the link so this is the get link from text and this is also private because this shouldn't be outside the Tweet controller we'll use this function inside share image tweet and share text Tweet now other thing that we need is getting hashtag and this is going to have a similar logic like get link so we can just have get hashtags from text then we are going to have a string text and then we are going to have similar logic so I'll just copy paste this but instead of string this is going to be list of string hashtags which is equal to nmt list as of now now we get the words in sentences and then we just check if the word starts with a hashtag so if the word starts with hashtag you're just going to have hashtags dot add word and then we are going to return hashtags so let me give you an example so if I have something like this but this time we have driven as well now this is in a list format okay now we Loop through it and then check does the word start with hashtag yes hashtag does We'll add it to hashtags does hashtag yup it has let's add it YouTube has no www dot has no so we are just going to have two hashtag words so they are in the list right now and we'll return the list and this is also a private function shouldn't be outside the controller great now after having both of these things done let's create a tweet model so we have tweet underscore model dot dot and now we are going to create this tweet model and then we can jump into this function and call all of this and interact with the Tweet API so now we can have class tweet and let's decide what all properties should be there final string text final list of string hashtags final string link final list of string image IDs this image IDs are not image IDs they are image links sorry these image links will basically be the links that we receive after storing our images in the storage facility of app right basically in this section storage so we get a file over here we take all of these files uploaded to storage get their URL and then we upload it in our tweet model and based on this tweet we can check if it's empty if it's not empty then we can display them on the feed screen when we have to display the Tweet then we have final string user ID so the person who created the tweet and then we also need the Tweet type so we can go in the core create a new folder called enums and in your create a first enum which is tweet type enum dot dot this enum will basically help us decide which tweet to be used right I mean which tweet type it is so that we can easily display the Tweet onto the screen so it can either be text so we have text or we have image so we have image here and then we are going to have final string type constant tweet type this Dot type so here we basically have tweet type tweet type right so it can either be text image and if you later on decide to add some more options like GIF sharing and just emojis or whatever you can add them then we also need final date Time created at so what time the Tweet was created or we can just name this tweeted at then we need a final list of string of likes then we need a final list of string of comment IDs so whoever comments on this tweet their IDs a final string ID so this is the ID of the Tweet not the ID of the user the user ID is this so the basically the user who tweets this will add this uid and ID is basically the Tweet ID and this is final and reshare count we don't want to keep track of who we shared it and stuff we just want to keep a track of number of how many people have reshared it then we have other things needed when we get to the replying part but let's just ignore it for now now we can generate a data class we can remove dot convert we can pass in at the rate immutable and pass in constant aware now we can scroll down and here you can see when we want to convert tweet type to a map format like we want to upload it to database we have two map but it's giving us an error because there's no two map so you want to do tweet type DOT type and this will give the correct type because that's what we have mentioned in the enum text and image this is the type of this enum then we have tweet type Dot from map kind of message so for that we'll have to create an extension on this enum this was using enhanced genomes and now we are just going to create an extension on this enum called this convert tweet and this is an extension on string this will return a tweet type to enum and we are just going to have switch this so when we are having this so whenever two enum is called on a string that string is text then we want to return tweet type dot text if it's image so if it's case of an image we want to return tweet type dot image and if it's none of these there's default and then we want to return tweet type dot text so it's either a typo mistake or anything then we just want to return a text type so basically if we have something like text mentioned in a string format and then we called two enum function on it this will return to us a tweet type dot text easy so now we can go to the Tweet model remove all of this it's not needed we'll take map of tweet type as string because it should be a string and convert it to an enum or you can specify it more efficiently by saying to tweet type enum because in case you have other enums on the string format later on an app you don't want to mess things up and then obviously we'll remove the two Json and from Json similar to our user model now we can come to the Tweet controller and first thing we are going to have a look at share text tree so here we'll set State equal to true that means is loading as started then I want to get a list of hashtags a final hashtag equal to get hashtags from text and we'll pass in the text that we get from here then we also want to get the link so link is equal to get link from text and we'll pass in the text then we are going to create a tweet model so we have tweet tweet equal to to eat and now we'll pass in text hashtags links now we need to pass image links image links is going to be empty for your then we need uid the uid of the user so we need to get the current user's ID so we'll have to do that tweet type here is going to be tweetype dot text because we are in a share text to it function so obviously it's a text tweeted ad is going to be date time dot now you can either use date time dot now or you can use the one that's given by apprite itself then we have likes likes is initially going to be empty comment IDs comment IDs is going to be initially empty ID so the ID is going to be empty for now because we are not adding that to two map and of course we need to remove that before we forget so in our tweet model we'll go and remove map of ID we don't need that actually in two map not from map so we'll remove from here we don't want this line and over here we are just going to a map slash dollar ID this is the same thing that we did with user model we don't want the from map to have just ID it's going to be slash dollar ID and this is not going to have a map returning ID okay so we can go to the Tweet controller again now the ID is empty and the reshare count should be zero one thing that's needed is the uid so to get the uid we are just going to a final user is equal to now we need access to refs how am I going to get ref inside of this state notify so to do that I'm just going to ask it from here I'm just going to ask it from The Constructor that yeah please give me ref I don't mind it being a widget ref a provider ref or just ref so I'll just ask it so we have required ref ref and then we have underscore ref equal to ref now I can take this underscore ref put it away or another ref dot read current user details provider dot value and then we'll pass in user dot uid so we get the user's ID and we pass that as a uid because only the current user can tweet from your account I hope that makes sense now we have the Tweet model ready and everything good to go only thing that's required is to create the Tweet API so that we can send it to the database so again let's come to our apis and create tweet underscore API dot dot we are going to create an abstract class for I tweet API and this is going to be future either document share tweet and we are just going to get tweet model and based on that tweet model we are just going to convert it to map and send it across pretty simple this is actually very similar to the user API we did that for Save user data we got the user model we created a document the data was usermodel.2 map and we returned right that's it and that's exactly what we are going to do here we're just going to have class tweet API implements I tweet API create one missing override this is the share tweet function so I'll have async and now I need a try and a catch block we have added future either here because this is not going to be enough future provider obviously we are just sharing a tweet which is a normal future return data type we obviously don't want to encapsulate everything that has a future with future provider it really depends on the use case if you want to get some data and display it on the screen only then would I use a future provider otherwise State Notifier provider is always good so here what I want to do is a try and catch block so I'm just going to go ahead copy all of this I would recommend you type so that you have a good practice but I've already had a lot of practice with this before creating this video now I'll just have final databases underscore DB so that you know I can inject it through my provider we've already talked about it we're just repeating the logic I hope you're getting the hang of it so we're acquiring this and then we are going to have underscore DB equal to DB I'm going a bit fast where because this is already the logic we have covered anyways after creating the document let's import this app right constants but this time it's not user's collection we need tweets collection so we'll name this to each collection and then pass in the appropriate tweet collection ID so let's go ahead create a new collection called tweets copy The Collection ID don't forget it and paste it over here and now I want to get started with creating the attribute surveyor so that we don't get the error so the attribute here is going to be everything that's mentioned over here so I can just take text pass it in select the attribute type as string 255 required and go ahead and create now you can do this for everything I'll just fasten this process really quick while creating the attribute one thing is the Tweet type the Tweet type here should be of the string format because when we are converting it to map you can see over here we're having tweet type DOT type and this is a string this tweet type is basically what we had mentioned over here okay and another thing is the attribute key of tweeted ad this tweeted AD should be an integer why because if you see aware in the two map function we have tweeted at dot milliseconds since Epoch and this returns an integer so you want an integer to be present over here we can mark this as required and click on create and make sure to not add ID property to this tweet model or this attributes don't add the ID property you can add uid but don't add ID because this is a tweet ID that is being automatically generated and this tweet uid is basically what we are passing in the current user's ID when they tweet now in the Tweet API what I want is database ID correct collection ID should be tweets collection and the document ID should be tweet Dot ID right no why because if you come to the Tweet controller you'll see that the ID over here is empty we don't want an empty document ID so this is not going to be tweet.id just like we had for user.id for our user model where we made a mistake this should actually be ID dot uni because every tweet should have a different ID so that they don't merge with each other right and finally tweet.2 Maps should be the data now of course we'll return right so import fp.library and here we have to return a document so we can just save this so we have final document is equal to this and we can return this document so this is our function that's all that was needed now I'll just create a provider out of this so we have final tweet API provider we don't have to mention the type the robot is very smart to identify that and then we can return tweet API and pass in the database which is ref.watch app right database provider I hope you're understanding what we are doing we are continuously repeating the same things and that's what the whole tutorial will consist just many repetition of things one or two unique concepts are left about real-time and storage otherwise it's just about creating reading updating and deleting every single place you just need to have the correct logic and understand what to do when now we can go to the Tweet controller except from The Constructor a tweet API so we have final tweet API underscore tweet API required tweet API tweet API and underscore tweet API should be equal to tweet API now I can take this underscore tweet API and use it here so we have underscore tweet API dot share tweet we'll pass in the Tweet model it will give us some response of your final response is equal to await this and you also need async so we'll acing this now we have a response now you know how to handle failures and success right we have done this in the past in the user in the auth controller we just have to do res dot fold we'll either have left or right in case it's left we'll show a snack bar with l dot message and if it's right nothing as of now later on when we add reply part things will change also to ignore the warnings let's put a const at the places that's required so this is the text based tweet let's see if it's working just based on text tweet so I'm not going to enter any image here I'll just say hey and actually I have to bind this function I forgot it so we need State Notifier provider tweet controller provider will pass in tweet controller and a Boolean value so tweet controller is the class name Boolean is what we are returning over here and now we need to return to it controller we'll pass in ref and then we need tweet API tweet API is ref.watch tweet API provider and that's it there's no dot notifier on provider that dot notifier on state notify provider and state provider State provider is a simplified version of State Notifier provider but you are not going to use that because it's hardly ever needed because it's so simple like the value it consists and its use cases are so simple that it's not needed ours is a more complex topic I know I've been rushing through so if you're feeling under confident I would recommend you to watch it again or code it on your own don't just watch it because this is a bit complex now what I want to do is just go to the create tweets view we'll create a function for share tweet so we have void share tweet and then we are going to have ref dot read tweet controller provider because we want to get access to this tweet controller right once we get access to this instance of the class we can call the share tweet function which will later on check if it's image or text we are just going to text for now and then it will upload it to the database so you have tweet controller provider dot Notifier dot share Tweet now we need to pass in images we have passed that in text text is basically tweet text controller dot text and the build context and we are done now we'll also check if it's loading or not so your final is loading is equal to ref dot watch tweet controller provider now if it's loading so I want to show a loader so if it's loading or the current user is null then I want to show a loader otherwise the widget tree and now if I click on tweet nothing happens so I'll just restart also I'll bind the share tweet function to the done button right in the app bar since the function signatures match you can see I can put that in correctly so I'll come over here I'll say hello and then click on tweet the current user is not authorized to perform the requested action and there's continuous loading there are two things to be fixed so I'll go to the settings of the tweets collection I'll scroll down and add a role where all the users can create read update not update and not daily because Twitter doesn't allow deleting I hope as far as I've seen I don't get the option to delete so we can either create or read there's no updating the Tweet or reading the tweet and also we have to set state is equal to false I can remove the comments these are basically useless comments now I'll set state is equal to false now and then restart the application come back here I'll say hello and click on tweet you can see invalued document structure unknown attribute hashtags so I think I forgot to put the hashtags list I'll put that in and the size of the hashtag list is going to be 100 or 50 or whatever you want we'll click on create now we'll click on tweet and the Tweet has been uploaded so if we go to the documents refresh there's one document with a text of tweet the correct uid of the user tweet type of text that's right tweeted art is also correct there's likes comment IDs and image links reshare count and there's no hashtag now I'll try to add hashtag hashtag rivonawat and also a link so I'll just write www.youtube.com and now I'll click on tweet so it got updated now I'll come back here we have it here's the text here's the hashtags correct and the link is also correct that means everything is working fine in the Tweet type text format now I want the same thing to happen in image but things might change a bit differently in share image to it why because we have a list of file images to be uploaded to storage we'll have to create a separate API for that so I'm just going to go ahead copy everything from here paste it in and definitely make some changes first make this asynchronous share tweet is going to remain same tweet type is now image we have a list of image links to be put in I'll do that and nothing else is needed so now I need to go to the storage API API folder and create a new API called storage API we cannot do that with the Tweet API because it might congest a lot and also this storage API is not just going to be used into it right it's also be going to be used in user profiles when the user wants to update their bio profile picture and all of that stuff they will be able to access storage API again so let's create storage API I'm not even going to create an abstract class for it there's just one function so yeah final storage underscore storage and you have storage API required storage and underscore storage should be equal to storage simple now we want to upload future list of strings while list of string because we are going to get a list of files we are going to upload that to storage it will give us the download URL not really give us a download URL it will give us image IDs of that URL we can convert them in the form of links I'll show you how and send them out so that's why it's going to be a list of string and then we want to upload images and we have list of files right so we have list of files this is going to be asynchronous I'll get file import the dot IO Library and now I'm just going to have list of string of file IDs or file image links let's just call it image links which is equal to nmt list then we'll run a foreign loop again so we have four final file in files then we want to upload it to the storage so we have final uploaded image equal to await underscore storage dot create file this is the API of app right it gives us a method known as create file get file all of those stuff we just need create file so if the user creates a file then we need the bucket ID file ID file so we know file ID is going to be unique so we can have unique like this or we can just have ID dot uni then we need the file the file is going to be of the type input file so how do I get input file well you can just do input file and pass in the path path is going to be file dot path simple basically we are looping through all the files in this list we get this file we are converting it into an input file using its path and now we just add file to the image links so we have image links dot add uploaded image which is a file but this is not the file from dot IO you see this this is not a file from dot IO that we are using over here this is a file model that's created by apprite itself so if you do dot on this you'll see a list of different properties because this is a different class altogether this is not the file coming from dot IO it's coming from app right slash models.dot the same place we got account and session classes so here we have dot dollar ID we can add that and then we just want to return the image links from this function easy now to get the bucket ID what we need to do is go to the upright console go to the storage create a new bucket let's call this images copy this bucket ID go to Upright constants and register it so we are just going to call the static constant string images bucket which is equal to this and now we can pass an upright constants Dot images bucket easy enough now we will just create a provider for this and call this storage API provider and we'll return storage API but we need to pass in the storage and for that we'll have to create another provider because we don't have anything for Storage storage yet so we can go to the providers. create another provider and call this upright storage provider will pass in storage over here and it will also require a client that's it all the upright dependencies are similar to each other that's a plus point and now in the storage we can just pass in ref.watch app Right Storage provider now you might ask one thing if we are returning the file ID how is this a link and you're totally right this is not a link so we need to convert this in the form of a link so basically if you try to upload any file I'll just select a file I just uploaded a file from here and you can copy this you'll get a file URL right now you can see this but the point is the URL is not exposed over here so if you try to do dot URL or something try to find something it's not really there so what I'm going to do is just examine this URL I'll copy this go to the upright constants and create a static function for this so we have static string image URL it will return this function will return a string of image URL by taking image ID as a parameter and return this if I want to make it work on Android I'll have to pass in my IP address over here so I'm replacing all of this with dollar endpoint slash storage because my endpoint doesn't have a slash at the end so we have dollar endpoint slash storage slash buckets then there's the bucket ID so I can just have dollar images bucket which is this one slash files slash dollar image ID view question mark project and then we'll pass in the project ID and mode is equal to admin so this is how we are able to retrieve and see the image URLs pretty cool now I can go to the storage API I can add this so I can just do image links dot add app right constants dot image URL pass in the image ID which has uploaded image dot dollar ID and with this we have image links added a proper valid image URL is there great now I can go to the Tweet controller go to the share image tweet and you're just a final image length is equal to underscore storage API so I want to get access to storage API so I can just have similar to tweet apis storage API storage API and now I can again have this passed in so required storage API storage API underscore storage API equal to storage API now that I have storage API I can just have underscore storage API dot upload image then I'll pass in a list of files and the files are images I'll await this I'll take the image links which is a list of string and add it over here now I think this is all about image Tweet now I can go up in the storage API I'll just pass in ref dot watch storage API provider and we are done now let's try to run the application we have already configured the UI file everything over there now I'll select some images I think these three work well now I can just say hashtag Revan this is so cool and I can tweet it out we are getting this error because the current user is not authorized to perform the requested action and that might be because we are not allowing the user to upload images so to upload the images we can go to the settings add a role all users can create or read I don't think reading is also allowed so let's just allow creating the users cannot read update or delete anything that's for our admins so I can just restart let's just select images again this is beautiful and then click on tweet now it says that the attribute has invalid type valid was valid string must be more than 10 characters so basically in the databases I had earlier said that the Tweet attribute of hashtag should be 10 but that's not the array value it is the number of characters in the string so your hashtags should have a string they should be a list but the size of this list can be you know 50 60. this is not the size of the list this is the size of the characters present in a string so my hashtag rivan should not be like 10 characters it should be like 60 70 whatever should be the maximum size of the hashtag okay now I can just click on create now I'll try to post this error is basically if I scroll down we have to delete this image links attribute they cannot be 10. why I'll tell you because image lengths should have a string attribute there should be an array but their size over here is not the size of the list it's the size of the characters so how long is the link a link cannot be just 10 characters right so here they should have suppose 255 characters or something like that you can calculate it whatever is the size of the link and put that in if it's something else then perhaps something is wrong in your project or apprite SDK has changed I'll just pass in 255 and see what happens this is the character size of the string of the image links not the size of the array okay now I'll click on create then I'll click on tweet and I think the Tweet has been made so I'll just go to the documents and we have hashtag everyone this is beautiful we also have three image links but they contain my IPS I'm not showing it to you so this is working well now the next part is after tweeting you know image links correctly identifying all of them and uploading them to database we have covered a lot of tasks in this section now the next part is to display those tweets over here on the screen and we already have the foundations for it we have the Tweet model which is going to help us a lot but we still have to make more functions like getting the tweets and creating a UI card for that tweet so that you know it looks good just like the Twitter so let's get started with it and we have to start off by creating a new view not a new view it should be a new widget and that is going to be a tweet list widget so let's create a folder here named widgets and now we want to create tweet list this is a widget name so we'll have tweet underscore list dot dot and now I'll import material dot I'll create a stateless consumer widget and I'll call this tweet list also I'll import the flutter evapot library and now I'll create a tweets provider so basically I want to create a future provider that will get me all the tweets from the app right database so I can go to the Tweet API and now I'll Define another abstract class function which is going to be future either not future either since we want it in the form of a flood riverpod provider the future provider we are going to have future list of document get tweets now I'll just do command full stop create one missing override and now I'll do asynchronous and now I want to get all the tweets now how do I get a list of documents so for that I'll just use underscore DB Dot and see the function for it create documents create the documents delete get list list documents will give us a list of documents as the name suggests so I want the database ID the database ID is upright constants dot database ID collection ID is upright constants dot tweets collection and now I'll just save this in a variable so I'll have final documents is equal to await DB dot list documents now I can just do return documents but this is document list not doc list of documents so what I can do is documents dot documents and it will return to us a list of documents correct now I can go to my tweet controller so let's go over there and here I'll create a separate function called future list of tweets correct because I want to get a list of tweet here we are returning the documents in a list format here I'll convert all of those documents in a list format so I'll call this get tweets this will be asynchronous and then I'll get final tweet list is equal to await underscore tweet API dot get tweets now this tweet left in the list of document so I'm just going to map through it and convert every single one of them into a tweet so we can do that by doing tweetlist Dot map and this will give us a tweet now I'll convert this to a map so we'll have tweet Dot from map sorry I'll convert it to a model from a map so I can do tweet Dot from map this will convert it from map to a tweet model and then I can pass into it dot data like we've done before for user model but this time we are just mapping through it and converting everything to a list so basically we went through all the documents mapped through each one of them we got a single document and we convert it to a model now I can return this thing because it's now a list of tweets and since there's asynchronous it becomes future list of tweaks and now I just need to create a future provider out of this so I'll just have future provider name this get tweets provider then remove this and then I'll have final tweet controller is equal to ref.watch tweet controller provider dot Notifier now I can return tweetcontroller Dot get tweets and now this is of the type future provider list of tweet why was I insisting on future provider now you'll get to know because future provider gives us a very good thing so if we come to the Tweet list and do return ref dot watch and then we do get tweets provider you can see we have earlier used dot value to get the value of the list and then we could use this value we did this for the user provider so if we come back to our create tweet View we can see here we did this since this was a future provider we had dot value but now what we are going to do is not value but dot when I said you can easily transition between the data error or the loading state that's why we never had future either in there because if there's an error we'll get to know it over here so now if there is data we have to do something if there is an error we'll also get a stack Trace you have to do something about it and in case of load up we have to do something about it so first two are very straightforward we have already created something for them there's load up for loading there's error text for error so we have error text and we'll pass in error.to string and for data we are getting tweets and this is in a list format so if there is a list of tweets and we don't know its numbers so how many tweets there are going to be we don't know that so for in that case we can use list view Builder and now we can mention the item count which is tweets dot length and now we'll extract each tweet so this item count is the number of items that are there so there are tweets dot length number of items now I want to get a access to a single tweet so I can have tweets at Index this index is provided over here so I'm getting one single tweet by doing to each index in the item Builder property and now if I just want to test I can just have tweet dot let's say text pass to it and see if I'm getting the right thing or not now I can take this tweet list go to my UI constants file where I've already created text feed screen now I'll just replace this with a normal tweet list and obviously this has to be constant now I can restart and here you can see there are three tweets and there are three tweets over here as well that means our tweets are being retrieved successfully now I want to create another widget which is the Tweet card so let's create that so I want to design how my tweet card is going to look like so I can do that in a separate way separate class because it has a lot of stuff going in it and this is also going to be a stateless consumer so we have to eat card and we'll import the flutter riverpod library now I can return this tweet list from the Tweet list I can return this tweet card but obviously we'll have to pass in the Tweet over here I'll accept it through the Constructor over there so I have final tweet tweet and I'll require this through the Constructor so we have required this dot tweet so the error goes away now let's get to the main thing what do we want to return well first of all we want to return a column and in that column we are going to have children and in that children the first thing is a row why a row because we want to have a circle Avatar to demonstrate to you I'll show you one year is a circle Avatar the profile pic of the user then we have the name of the user here we are going to have reply so if there is any reply we will have that if there is a retweet there it is going to be above the username and then we are going to have the text of the user if there are any images the image of the user at the last we are going to have a divider so that there's a great division between the next tweet as well so we need a column so that we can accommodate the divider and then we need a row so that we can have the user avatarp or user profile picture along with their name so now I'm just going to return a row so that I can have a circle Avatar and this circle Avatar is the user's image and we'll pass in the background image but now we need the image of the user who has tweeted this we cannot do final current user is equal to ref.watch current user details provider dot value we cannot get their value by doing this this is not the image of the person who's tweeted it it's the image of the person who's handling the app right now so it will vary for every person we want to get the details of the person who's uploaded the tweet so to do that we'll have to create a new provider and actually we don't have to create it we have already created it and that is ref.watch user details provider here we just have to mention the uid of the user and that is tweet.uid dot when it will give us data error and all of those stuff in case of data we'll do something in case of error and loading we can just go over here copy both of these things come to the Tweet card and paste it now I can copy the column and your return column now to get the background image it's just going to be Network image and let's call this user so there will be user Dot profile picture now if I save this much you can see we are getting these profile pictures now they're the same ones as this user because it's the same user we created the tweet from your and we are viewing it over here but if you try it on a different device with a different login you'll see different images but if you use current user details provider it would have given you something else on a different device it would give you the same thing over here but it would be different on a different device because it would use their profile picture it wouldn't be the person who tweeted that their profile picture won't be available so you have to do this it's very important and don't mess it up because I've messed it up while I was developing this application now I just want to increase the radius so I'll just have radius 35 save it and this and this looks much bigger that's great now I'll just put a margin here so I can just have a container and put a margin of constant agencies dot all 10. so there's a margin of 10 everywhere and this looks super cool the next thing we need is a column we had a column first so that we could put in a divider then we add a row and inside of that row itself I want to put a column why because here we are going to have a list of things there is going to be username the text of the user if they are replying to anyone their reply tag if they're retweeting to anyone the retweeting tag and that images so it's all going to be in this column and then we are going to have children and then there's going to be retweeted thing but we are not going to focus on retweeted thing right now we'll focus on that when we add the retweet feature so you can just put a comment for now that we want retweet it to be there next thing is the row and this row is going to contain the username the user name with other it and the number of hours it has been since they posted so it's going to be again row this is a bit complex design then we need a container because we need to put in a margin so we have margin Edge and search dot only from right side we want 5. and this will be constant and the child will be text user dot name because you want to display the name of the user who has posted it and now if we see this is test this is good as well now I just want to style it up a bit so we have constant textile and then I'll pass in font weight as font weight dot bold and font size as 19. if we save this much and come over here this looks good we have put a margin of 5 here because the next thing that we are going to have is the user name with at the rate as well as the time ago it was posted so here we are going to have a string and this is going to be at the rate but this is going to be interpolated like this so at the rate is there then the user name that's a variable and thus we have this but now we have to change this a little bit so here the font size should be 17 and color should be palette dot gray color if we save this much this looks good the font weight should go away and now this looks nice now we want to put the time ago it was posted and to do that we are going to use a package known as time ago this will calculate the time ago it was posted so we have tweeted at property which will give us the time it was posted and time ago will calculate the time from right now to when it was posted and give us give it us in a format like four hours ago five hours ago something like that then I have the dot with me and then I can use dollar time ago dot format now I want to import time ago so I can just do import time a go dot dot as time ago now I can go over here and have time ago dot format tweet dot Twitter Dot and if I do this much and see over here you can see test user was three hours ago now I just want to reduce this to 3 H so that there's not much space taken so how I can do that is just by adding which is en underscore short so this will shorten it and now we just have three h over here not three hours ago that's a very big thing now the next thing in the column so we'll get out of this this column as well sorry we'll get out of this row and then we'll have another thing which is replied to so if there's any reply to we want to add that tag but we will do that later on when we add a reply feature then we need a text so we can just have a simple text right but we also want to identify hashtags or links in that case so how can we do that well for that we are going to create a separate widget called hashtag underscore text dot dot we're going to import material dot we are going to create a stateless widget called hashtag text we are going to have final string text and require it through the Constructor so we have required this dot text and here since we want some parts colored in white which is a normal text and we want some part to be colored in blue so for that we'll have to use text man so we'll have a list of text span over here so we have text spans which is equal to an empty list and then we can do text Dot split so that we've split all the words in the sentence we have already looked at this logic and we'll run a for loop on it we can also run a map for each whatever you prefer I'll run a for each Loop and here I'll just check if the value or the element so if element dot starts with #so if it starts with hashtag I want to add a text pan to this text spans list second half text pans dot add text span the text will be there which will be dollar element and in a string format and we leave a space here why have we left space we have left space because you have left we have split the sentences by spaces so we have a list of words so if we add rivan ranavat as a sentence and then now we have ribbon in a list format with ranavat now we are just adding them so we have rivan added together so we have everyone and then run our there's no space between them right so we have to leave a space then we can have style which will be constant textile color will be palette dot blue color and font size will be 18. bigger than the normal and let's also bold it so that you know it looks a bit different so we have font weight dot bold now as if the value Dot not value element dot starts with let's say www dot or http so we have https colon slash slash then we will have something similar so we'll have text pans dot add this this is also going to be blue color and bold and all of that stuff let's just remove both so that there's some distinguishing Factor and else will be the normal text so we have text pans dot add we add the value but this is just going to have a font size of 18. it's not going to be blue color it's just going to be the same size as these two three or these two and now what I want to return is a rich text because it requires a widget to be returned and here I'll pass in the text as text pan and it will have children as text pans so you have returned a rich text widget with a text span having its children as it expands that we just created over here and now I can just have hashtag text pass in the text which is tweet Dot text and now if we come over here you can see the UI is totally dismantled but we are getting our hashtags and links colored this is great now to fix this what we can do is wrap the column widget over here with expanded widget since we are in a row container takes this much and then we have text that's overflowing so we want text to get all the maximum space and if there's no Magnum space it can just go down so we'll just wrap this and if we come back yep it looks fine now but you can see this text is not in the center is in the center we want it to start from here so we can go up here again wrap the column widget with cross access alignment as cross access alignment dot start paste it and everything starts from the left side now the next thing that I need is images to show up so if tweet dot tweet type is equal equal to tweet type dot images so if we are having an image as the tweet type then we want to do something braces are not allowed while rendering this this is an if collection so to have that we are going to create a separate widget on its own and that is going to be called Carousel image dot dot we can import material Dot we can create a stateful widget because there's a lot of stuff going on here basically we have an options button so if the user wants to know which image we are on or if we want to click over there and go to a certain image they can definitely do that and this is going to be final list of string image links we'll require this through the Constructor and now where we are going to create a variable called end current is equal to zero this means the current index of the image to be displayed is 0. and now we are going to return a stack and there is going to be children why is it a stack you'll get to know our first child is now column the column is now having children and the first child is the carousel slider the carousel slider is the same thing as what we had in create tweet view so we can go there copy the carousel slider mentioned there and paste it in the children now I can import Carousel slider I can map through the image links or widget dot image links then do image.network where we'll get a link and based on that link we have to do image.network and this will have a fit of box fit dot contain and here the margin is going to be in all the sites so we are going to have margin dot all 10. now just to see if it's working we'll have Carousel image we'll paste it over here pass in the image links which is tweet dot image links and save it and when we try to see the surveyor we are getting this error this is because it is not able to fetch the images and for that we have to give them a proper permission so in the storage we'll have to go to the images tab go to settings and your add a role for any user that they can create grid update delete and then click on update now if you restart the application you can see all of the images showing up so the error is now gone now let's beautify this further how can we do that first of all in the carousel slider we want the viewport fraction to be one we want to disable the infinite scroll and this looks much bigger already that is nice and in the stack we want alignment as alignment Dot Center so it's right in the center also the width will be removed here and the decoration of box decoration border radius border radius dot circular 25 will be added let's see if this much and here we are going to have one more thing on page changed we'll get index and reason and then in the search state we are going to set current variable that is global equal to index so whatever Index this arousal options give us we'll set that to the global variable current now the next thing after this is row widget because we want to display a bunch of circles so that we know how many images are there and stuff so in the children we are not going to return a list where we are instead going to have widget dot image links Dot as map dot entries so we're going to treat them as map and get the entries and map through each entry and return a gesture detector we also convert it to a list so that we don't get any error right now we are getting entered because you're not returning anything so we have to return a container which has the width S12 the height as 12 and margin will be Edge in sets dot symmetric in the horizontal Direction we'll have 4. and this will also be constant and now we want to create a circular shape so we are going to have box decoration shape as box shape dot Circle and color will be colors dot White dot with opacity and the opacity will differ because if it's current so basically if current is equal equal to e dot key e is basically this one so if the current matches the current index we are on then we want the opacity to be more right so it will be 0.9 otherwise it will be less opaque so we'll have 0.4 and here you can see we are getting this thing looks good and this was the entire Carousel image we had Carousel slider and then we had a row depending on where we were so now if I just try to you know go back and forth you can see we're getting the correct highlight on this now in the Tweet card we have to make certain changes again so we'll go at the top in the row you can see we have cross access alignment we have to pass in Cross access alignment dot start so that you know our Circle Avatar moves at the top not in the center then we will have another thing which is if you want to display the link so if tweet dot link not likes link dot is not empty so if tweet.link is not empty that means we can display a link and it has identified a link for us to display then we will leave some space from the top so if we have constant size box height 4 and then we will install a package called any link preview this will open up a preview of any link as the name suggests of the package and to use this we just have to do any link preview we'll get a link so we have to pass in the link which will be https colon slash slash dollar tweet dot link let's import the any link preview package save it and here it is and it's not displaying as of now because we have to restart the application so let's restart it and while that is happening let's get on to the next step which is the icon buttons to show up below the tweet so basically like comment all of those things so here we are going to have another feature or another widget called tweet icon button dot dot we will import material dot for it we are going to create a stateless widget called it tweet icon button then we are going to have final string path name the path name is the name of the part to the flutter SVG icon that we are going to use then we are going to have final string text so what is the counter how many tweets have happened so how many retweets have happened how many likes have happened all of those stuff and avoid call back tap so we avoid callback on tap now we just need to generate a Constructor for all of this and now we are going to return a gesture detector so any of this is Click what should happen and in the on Tab we'll pass in the on Tab and in the child we are going to have a row and in that row we are going to have children of SVG picture.asset at first and what is the path name well that will be decided from The Constructor whatever value is passed through the Constructor then we need a color and color will be palette dot gray color then we need text and the text will be text that's from The Constructor again and style will be constant textile font size 60 so it should be smaller than the tweet text that is showed up and obviously we need some margin so we can have a container and have margin constant Edge and such dot all six save this much you can see our links are also showing up but I don't want my link to show up like this I want it in another format which is which can be changed through display Direction which is UI Direction dot UI Direction horizontal and now it's in a different format I like it in this format so after this link we need to pass in our tweet icon button that we just created and before that we want a margin from top and right so we are going to wrap it with a container so that everything doesn't stick together right so we have container then we have margin and then we are going to have constant Edge in such dot only from the top I want 10 and from the right I want 20. and the child will be a row and the row will have children and the first child in this is going to be tweet I can button there's going to be path name so the path name is going to be assets constants Dot View icon the text is going to be 0 as of now and the on tap is going to do nothing let's see how this looks here it is looking good also I can have main access alignment as main access alignment dot space between so that when we have more icons it will look better not congested now also in the text I just realized the views can be counted like tweet dot comment IDs Plus not plus comment IDs dot length Plus tweet.reshare count dot length this doesn't require link because it's just integer and then tweet dot likes dot length and convert all of them to a string and display it out so this has 0 right now now the next tweet icon button is of comment so we have comment icon and this is just going to have tweet dot comment IDs dot length Dot tostring so let's remove this and this looks good now the third icon we need is a retweet icon so we can have retweet icon and this will be reshare count dot to string great now the third fourth button that we need is a like button for now we are going to have this but like button it's going to be a little bit different because of the animation we are going to add to it and the text is going to be likes dot length dot to string and the final button we are going to have here is not going to be a tweet icon button it's actually going to be just an icon button because I didn't find the need to find an icon for it and it's going to be constant I can ikins Dot share underscore outline now if you see a wire this looks good you can change its size by having size as 25 and color AS Palette dot gray color now let's just leave a space after this container so we have constant size box of height one and at the end of this column you see this was a big row I told you that we added the parent column so that we could add a divider at the end so I'm just going to have a constant divider over here and this divider is going to have a color of palette dot gray color sweet and now we have this this looks superb if you put this divider over here instead this will only cover this part of the row that's why we didn't add it over here we added it right below the last column and this looks much more better and this also concludes the entire UI right now other things like the like animation replying part the retweeting part will add them as and when we get to it right we just don't want to mess everything up and put everything together the next focus of this app is going to be making stuff real time so basically if I try to you know tweet here like hello and tweet it out come over here you can see Hello is not shown this hello is the previous hello three hours ago not the current one only when I restart my app can I see the hello here so I want this hello to show up real time so we'll have to use real Time That's provided by app right over here and it's going to be very fun so let's get into it but before that let's see why our UI looks so off with this part right here we have three buttons over here we have an image but this looks very weird because it takes a lot pay more space than expected one problem is the high touch taking so if we come back over here we remove this height and come back you can see it takes only that much height that it's needed it doesn't require all the height correct and these buttons over here they are not centered we want them to be centered so we can have main access alignment as main access alignment Dot Center and now they're right in the center and this looks more Compact and better now let's get started with real time so to get started with it we are going to go to the Tweet API create our abstract class which is to get latest tweet so in the abstract class here we are going to create a stream this real time gives us a stream and it will give us a stream of something known as a real-time message and it is going to give us one latest tweet so let me just type it out get latest tweet it's not going to give us you know a list of tweets that are new or anything like that it will give us one single tweet that just came in real time works like socket so it is just going to give you the latest event that it has and just present it to you so that you can display or do whatever you want to do with that so now I'm just going to create one missing override come over here and now we have to use real time now to use real time of course we'll have to import it from The Constructor so let's have final real time underscore real time here then we are going to require this so we have required real time real time and then underscore real time should be equal to real time that we are getting from the parameter here easy now we can go down also let's see why we are getting this error we have to provide real time now real time is provided by app right and for every single app right dependency we have created a provider so let's just go over there and create a last provider which is the app right real-time provider you can see how our work is getting reused every single time we use a provider we don't have to continuously create instances only one time we have to create this and it works well for us in the entire application here let's just provide real time which is ref.watch real time app right real-time provider now we can come down here and return something so we need to return whatever will be returned so let's just call it real time and see what it does so if we do real time and if we do subscribe you can see we can subscribe to a list of string of channels so let's just first have a string and then just see what subscribe method gives us it gives us a real-time subscription but here we want to return a stream of real-time message so over here we have something known as dot stream that will convert this into this format now we need to subscribe to a particular Channel now what are these particular channels you can find a list of them on the app right documentation it's present over there or otherwise if you want to understand it logically from the point of view of database so let's just go over there we are going to use real time for databases so if there is any changes made in the database in a particular collection or in a particular document we're going to track it through this subscribe method of real time but if you want to do the same for storage so for a particular file or a bucket you can do that and the channel name for it is present in the description below basically you'll find the app right documentation where you can find literally everything well written so let's just go to the database now let's understand what we need to track we need to track the tweets collection and see if any tweet is being created right so for that what are we going to do to understand that let's go to the main app right dashboard so first thing we need to do when we are in our project is go to the databases so we need to enter a database ID right so here we can just have databases Dot so it will go to the databases and then we want to go to the particular database ID so now when we go to the particular database ID we need to enter that as well and a database ID is present in app right constants dot database ID now after databases where do you want to go to a collection and that is the tweets collection so we can just write dot collections over here and after that dot dollar app right constants dot which collection the tweets collection because we want to see if any tweet is being created and then we just want to keep track of the documents we don't want to track any particular document because we want to track if a new tweet is being created or not so here we're just going to have dot documents and that's our entire Channel we go to a database by and then pass in the database ID then we want to go to the collections pass in the collection ID and then we keep track of the overall documents not just one particular document if you want to do that you can do document dot dollar app right constants with a particular document ID but not that for my case right sweet so our get latest tweet is now done it will give us the latest tweet that it gets if it doesn't give any latest tweet there will be a loading indicator you'll understand that when we write the code for it in the UI file but before that we need to convert we don't even need to convert it actually I was going to say that we need to convert this real-time message that it gets in the form of a tweet but we don't need to do that because in the UI file we need to check some things we need to check that if the Tweet is being created or it is being updated or it is being deleted whatever here we have just told we need to keep track of the documents don't forget to put the S over here we need to keep track of the documents but we don't know what event is happening on it it can either be creation deletion whatever so for that we are going to create a stream provider and let's just call this get latest tweet provider will remove the async star we are going to get an instance of the Tweet API directly we're not going to get an instance of tweet controller what we have been doing till now because we are not going to register this function in the Tweet controller because we don't have any job for it so now we can just have final tweet API is equal to ref.watch tweet API provider and now we can return tweet API dot get latest tweet of course you can put this function get latest tweet in the Tweet controller as well and just call underscore tweet API Dot get latest tweet and then use the controller over here but why do we have to do so much when there's literally nothing happening in the controller for it so we just tap this now of course if you want you can add Auto dispose Auto dispose will Auto dispose your provider and it's always a good thing to add beside every provider I've forgotten to do that so go ahead add Auto dispose everywhere it will be mentioned in my GitHub repository so if you are referring to that I'm sure you'll find Auto dispose over there it's similar to dot family so these are two modifiers on providers you'll get them on stream future providers you'll also get it on the normal provider anyways now let's go to our create tweet View not create tweet view sorry the Tweet list and here we are also going to watch for getting the latest tweet so right now we are just watching the get tweets provider which is a future provider now we want to do it real time and if there is any changes in real time we're going to display it in the UI if you don't understand this I'll explain it to you through a diagram so we have our device over here a very slim device and we have a list of tweets that are showing up okay now these tweets are powered by Future provider as of now they are not real time they basically build only once when the app is loaded and since we are using stack even if we go here and come back it's not going to change what I mean by this is since we have used index stack and if we scroll down it will process the state and it will come back to where we had scrolled basically it's not rebuilt in this entire project so the future provider is not going to get rebuilt anytime but now what we want is our app look real time now to make it look real time you had added real time which is something provided by app right and no external configurations are required for it so after we get those latest tweets we are just checking if another tweet is being created or not if it is being created we can get it from the real time so here instead of returning list view Builder directly what we are going to say is have basically another real-time provider here it constantly listens to any changes in our mentioned channel the channel what was what we had mentioned over here so it continuously listens and if there is any change so if there's create update it will directly affect in our application that's how we are going to create it so the data from future provider shows up but the data real-time provider gives us will be added to our data to be rendered on the screen if you don't understand this let's write the code and I hope you'll understand after that so right now what I want to return here is not a listview Builder I'll just comment it out I want to return ref.watch get latest tweet provider dot when and when we have data when we have error along with stack Trace and when we have loading we have to handle all of these states so this is what we want to return now in case of error and loading we add this but in case of data what do we want to show well that's the point we are getting a real-time message here so let's see what the real-time message gives us it gives us channels so the channels we subscribe to events so what events are happening payload so what data is there inside of the real-time message so basically what exactly is the data that got modified that will be mentioned the timestamp so what time was it updated or created whatever so we have all of this now what matters to us is first we want to check if the data was created or it was updated so if it was created then we want to insert it into our array and our array is tweets.link we want to insert it into it but if it was being modified then we want to send the modified data inside of this tweets array so let's write the code for this we are just going to check if data dot events so what was the event was it being created or updated so this gives us a list so we want to check if data.events contains some event so what is the event we are looking for well it's very similar to this let's go to our tweet API so we have this and then we pass that in so we have if database.evens.contains databases and here we are going to have dots star that means anything any database and the collection should be apprite.tweets collection so let's have that dot documents Dot any document dot create now I'll explain this code to you but let me just format this a little bit so what just happened here so if data events contains this part so the data that we got right now if it was being created then what do we want to do so to check if it was being created we went to databases dot star so it can be any database I've done this any because right now we just have a testing database that means a debugging database if you release this app on production you'll create a new database how will you do that if you go to the app right console go to your Twitter clone application in the databases tab you can create a new database you can see that so I did dot star so that it works everywhere dot collections and then the upright tweet collection dot documents dot star so we want to check for any document not just one document any document and if create is there then what do we want to do we want to update the tweets because that is being returned in the list view Builder correct so let's just take this and put it right here outside of the if condition inside this get latest tweet provider so if it is being created what do I want to do I just want to show it up in the list so we have tweets that is being used to display the tweets over here right so I can just have tweet dot insert now we can do tweets dot add or we can do tweets dot insert we are using tweets dot insert not tweets Dot add because tweets.ad will add the to eat at the last of the list we don't want to add it in the last of the list we want to add it at the top so here we are just going to have tweets.insert 0. so if we do it at 0 it will come right at the top of the list and then we want to specify the element right don't worry using insert will not replace any element all the other elements will shift and insert will just add the latest tweet to the start and now we can just have tweet Dot from map and then we'll pass in data dot payload I told you payload contains the data the actual data so we can just use payload so every time this happens we are going to insert 0 comma data.payload and this is cool so let's restart our application and here you can see we're continuously getting the loading indicator now if you want to check which loading indicator is this this one or this one you can go ahead and print it but I know that this is coming from this loading because earlier this works fine now why are we getting this loading now how Real Time with upright works is it keeps on loading until we get a trigger so basically until an event gets created so until this create have or update or anything happens we keep on getting the loading indicator and if you don't use riverpod you won't even get to know that it is being loaded you won't get anything in the terminal you won't see anything on the screen but inside of it it's not actually loading it's just saying that it doesn't really have any data right now so it just keeps on loading over here because data loading is the state where there is no error and there's no data right so how can we fix this problem well my solution to this was just returning a list view Builder over here so the exact same listview Builder that we are having aware can be passed in the loading indicator and now if we restart we get the Tweet showing up correct and now if you want to test our logic over here we can go ahead create a tweet so I'll just say hello what's up and I can click on Tweet now if I go back you can see in real time hello WhatsApp shows up if I remove this line these two Logics and try to rerun the application you'll see that real time doesn't work we'll have to reload the entire application but with real time everything works well real time now if you're still not clear about the loading indicator and how this entire process work let me brief you through it if you have understood make sure to skip forward to the next part so basically what we're trying to do here is just getting the tweets provider first so we have a list of tweets with us after we get the list of tweets with us we are continuously checking if you are getting any latest tweet provider or we are not getting any latest tweet so once we get the latest tweet we are going to get a data and you have your checking if the create is being triggered on a document if the Creator is triggered on a document we just convert it to a tweet model using the data.payload which consists of the tweets data and insert it to the top of the list and since this has changed our list view Builder will also change and it will rerun this part but what about the loading part what did I mention there well you saw continuously the loading indicator was being run that was because there was neither any data nor was there any error because real time gives us data only when a certain event is triggered so if a create function is triggered update delete any of this is called only then will data have some value otherwise it will have no value it will no have no error it will just keep on loading so to fix that what I did was add a list view Builder here so as long as it's loading just show a list view Builder but anytime we get some data over here which is a stream provider right so it can continuously listen so as soon as we get some data this will get triggered and this entire function will run so we'll come over here now if you still don't understand I would recommend you to print the loading over here and print data aware and see how it's working by restarting the application that will give you a sense of what's Happening okay so now the next thing that we need to work on is if you see when we restart the application our hello WhatsApp goes down I want my latest tweets to show up right at the top so what I can do is go to my tweet API in my get tweets function I'll add something known as queries queries will allow me to add like queries to my application through which I can make many changes to add queries you can just do query Dot and you can see a ton of options it gives you before these two are used for pagination and they are very efficient that limit also used with apagenation offset also used for pagination their uses can be seen in the upright documentation or if you want I can create a separate tutorial on it I'm not going to cover pagination in this tutorial then we have order ascending or order defending so basically in what order do we want to arrange our tweets well for us order descending order ascending is what is showing up here the last tweets or the older tweets show up first but we want it in an opposite order order descending and what is the attribute so what is the property According to which we should put it in the descending order well it's because of the time so we'll just have tweet it out so based on tweeting at I want my documents to be listed other queries here are equal to greater than search we are going to use some of them later on in the application when we go to the searching users part but for now let's restart our application and here you can see we are getting this error we are getting this error because whenever we create an attribute or a query we need to register it in our database so here you can see whenever we have a new property to add we can add it over here but whenever we have some index to be added this is all index so whenever we add indexes to add we need to click over here create index so what is this index going to be called tweet defending then the type of this index is key the attribute here is tweeted at and the order should be descending now I'll click on Create and our index is now created now if I try to run my application you can see this works six minutes First shows up then 17 hours 20 hours 21 hours now if I again try to create a tweet let's say hello with many exclamation marks but other thing is whenever I click on tweet I don't pop off the screen so to pop off the screen I have to go back to the create tweet view where we have created on sharing tweet we just have to call Navigator Dot pop we are not adding pop in the share tweet over here right after here we are not adding it over here the reason for that is this share tweet will be reused in another feature which is replying to tweets anyways now let's try to tweet it out and our screen has popped off and if we just go up you can see Hello with many exclamation marks showing up our app is now real time now the next thing we need is this like button we want this like to work so the first thing we are going to do is animate the like button to animate the like button we have to go to the Tweet card and here first of all I'll just add a dependency of like underscore button this button gives us the nice animation of Twitter um and here we want to scroll down and we want to replace the like outlined icon with this like button so we have like button over here let's have that and now we'll give it a size of 25 so that it matches with every other icon then we have to have a like build up so basically if it is liked what do we have to build I am based on this like so I'll have is liked so if it is like let me just have this so if it is like then I want to return so I'll just have return is like and if it is like then I want to return SVG picture dot asset and I want like filled icon so I can just copy this and just have like fill icon and obviously if it is not then I'll have this thing but with like outlined IQ okay now I just need to mention the color and stuff so if it is filled we are obviously going to get the red color so I'll have color palette dot red color mind if it is not then I want color to be palette Dot gray color all right now let's see if I try to click over here nothing really happens let me just remove this and now if I try to do this you can see we are getting the nice effect now after this we also want to show the like count so we'll have like count and like count is basically tweet dot likes dot link we'll save it and here we see the counter but now I also want to change the color of this counter so now how can I do that I can just have count Builder passed in it will give me these three properties like count is like and text so here I can just pass in a text I'll return text and pass in the text with a style and the style is going to be textile and really depends what should be the color so the color can be red if the tweet is light and if it's not like then it should be white so we can have if it is liked so is like so if it is like then I want to have palette dot red color otherwise palette Dot gray color and obviously mention your color I also need the font size so we can have font size and pass n16 over there because right now it feels very small now I can save this much go away it still looks out of place because this should be white color now after having this it matches with the rest of the things but still let's just add a little bit of padding from left so I can just have a padding widget and from the left I want two to be present I'll save it and this matches with other things now so if I click over here the counter increases and if it's not then it doesn't now we want to get into the actual liking part so I'll go to the Tweet API and here we are going to create our next function in our abstract class which is going to be liking the Tweet so we're going to have future either document we are having future either not future because as I said not everything that our future needs to be in the future provider and we'll get like tweet over here and we'll just accept tweet from the model aware now we'll create a missing override for this go down pass in async then we need a try catch block all of those stuff I would recommend you to type it I'll just copy it and paste it down here okay great now after having this now let's understand how this liking feature works well basically I want to go to my particular document the particular tweet that has been clicked on and liked I want to go there I just want to increase the likes over here so basically I want to add likes to this array and this should work I like to eat is now complete this is exactly what's needed so I want to update this document so let's find if DB has anything like that and it does have an option of update document so we are going to use this we'll pass in the database ID The Collection ID the document ID the document ID is not going to be ID dot unique anymore because you want to update a certain document the document that was clicked on and we are getting the document ID from this tweet that we are accepting from the parameter so we can just tap tweet dot ID for the data we can pass in a map and here just say that you want to update one certain attribute over here which is the likes field and here I just want to pass in tweet dot likes okay if you're wondering why are we having tweet dot likes won't the likes be the same as before then well no because when we use this like tweet in our controller we're going to update this tweet model so when you're on the street we are going to update the user model to have the users like so the user's ID in it and then only we are going to send it to the API so basically we'll just go to the Tweet controller we will have a new function created which is like tweet and here we are going to get the Tweet model so basically whatever tweet we are going to have over here this is going to be the old tweet before the updating what does the Tweet look like and the user model of the current user we can get that from ref.watch as well but if we use it right now where when the user clicks we will get an error because it will think that the uid is null you can try it on your own by using ref dot read current user provider dot value but you will get the error so we are directly getting it from the tweet card itself now we are going to have list of string of likes so what is the likes well it's just tweet dot likes right why are we storing this in the likes variable independently well because there's a lot of logic to put in here so if the Tweet is already liked suppose it's this way and the user again clicks on the like button we want to remove the like and if the like is not already there and we click on it we want to add it to the likes array so here we are going to check if tweet dot likes dot contains user dot uid so if the Tweet like array contains the user's ID that means that the user has already liked it and it he has already clicked on the button so the case is right now like this the user has liked the tweet and we want to click on it so basically we want to remove the tweet to remove the Tweet what can we do we can just do likes dot remove and what should the value be well the user.uid so you want to remove the current user's ID else the Tweet dot likes does not contain the user ID and we want to add that user ID so we can have like likes dot add user dot uid simple now we will set tweet equal to tweet dot copy value remember that copy with function that we created since the likes field is immutable so basically tweet dot likes as immutable I cannot update its value actually for an array I can do that but this cannot be done for another field so example tweet Dot ID you cannot set it to something else you know it will give you an error ID cannot be used as a setup because it's final so you cannot do this but you can do this for an array because we have not returned an unmodifiable array or mod unmodifiable list anyways we're going to have copy with so basically what we are doing is setting tweet equal to tweet.copy with so we want to update a field and the field is likes because we have updated the likes field according to our logic here and we are updating the Tweet accordingly so now the tweet has updated like number or the updated like array now I can just do final result is equal to await so let's put async over here and have a weight underscore tweet API dot like tweet and then we'll pass in the street and that's why we have directly put in like likes is tweet dot likes we do not have to do tweet.likes dot add or remove all of the logic has been put in the controller over here and then we can just do res dot fold in case of a failure we don't want to show anything in case of a success we don't want to do anything why do we want to show nothing in case of failure because it's a like button that's clicked on have you ever seen a message that when you click on a like button you get any error so you don't want to show any error even if it is there and also you might notice that we have not set status equal to true and state is equal to false because whenever we like a tweet we don't see a loading indicator right that's why now we just need to bind this to our like button over here so we'll have an ontap function is like and now we are going to have ref dot read tweet control of Provider dot Notifier dot like tweet we know all of this now we have access to tweet as well which is the user tweet we are getting from the Constructor and we also have access to the user model which is the user who has created the Tweet but we don't want the user who has created the Tweet we want to have our own current user right we don't want to check with this logic that if the Tweet dot likes contains the person who has created the tweets their ID we don't want to check that we want to check if the tweet. likes contains our own uid so that's why this user won't work we have to get final current user which is equal to ref dot watch current user details provider dot value and now we are going to check over here so if current user is null so if current user is equal equal to null then I want a loader to show up otherwise this or even if not a loader we want a sized box to shop anything works now we can just come over here I have this and see why are we getting this error we're getting this error because it requires a future Boolean so to make a future we love ad async and now we want to return a Boolean so on tap should the like change so yeah it should change so vlab is like this is like variable gives us whether the Tweet was liked or disliked here we are just saying if it was like then we want to return opposite of Light which is not liked and if it was not like now it is light right now we can restart the application and let's find this particular tweet the hello tweet it's this one only so now I'll click on like button over here I'll click on restart and we're not getting anything in our likes array the reason for that it's very simple if we go back to the settings the current user is only allowed to create or read it's not allowed to update or delete so you want to allow the updation as well now after updating let's go to back to our documents restart the app now if we click on hello you can see it was updated and if we go to our hello document the likes is present over there and if I again click over here the likes was removed if I reached fresh the lights was removed this works fine but there is a problem if you see they're not getting the circled over here why and also if you see the view counter increased in real time no other tweet increased its view only this particular did so to make this animation work let's go to the like button and see there seems to be some problem with the is liked part so here we'll just add an is like the option so when is the like is liked it requires a Boolean field so when it's liked it is liked initially only when it is when tweets dot likes so let me have tweet dot likes dot contains my user ID so we have current user dot uid so if the Tweet dot likes contains the user ID then its light will be true otherwise it will be false and right now it contains it so if I remove it it doesn't contain it now if I put it back it contains if I remove it it doesn't if I put it back you can see it contains otherwise it doesn't now to give you the second answer that is why does this work why does this real time work well this is because of how the Tweet like button works this is not really happening real time because of our real time tweet list call over here the thing we've put here it's not happening because of that this is happening because this is how the like button package works it automatically updates it listening a task and since this Updates this will also update because tweet.lights.length increases now that we have this the like button also seems to be working the next part is now clicking on the retweet so whenever we click on the retweet this counter should update and a new tweet should be added with the same users ID so this should be there the same tweet but above should be written that test retweeted or some other like Revan tweeted retweet it sorry so you want that tag to be appearing so first of all we'll start off by closing all the save files will again come to the Tweet API and here we're going to create a new function in our abstract class and this is called update reshare count because only we only want to update the reshare count so this will be the exact same thing future either document but this time update reshare count we'll get a tweet this is exactly similar to the like feature but instead of adding a new likes array we are going to update the reshare count and this should be asynchronous and after updating the document we don't want to update the likes array we want to update the reshare count so if we go to the Tweet model and see what the name was it was a reshare count and this should be tweet.tree share count easy now similar to the like feature we are going to update this reshare count counter in our tweet controller so we can go over there we can copy this void like tweet and avoid re-share tweet so we get the current user so let's just type in that we want a current user and we also need a build context because if there is a problem while re-sharing because it is a big process you basically want to create a new tweet and save it to our database we will display an error in case of any error so what do we want to do here well let's just remove everything we will call reshare update reshare count and pass in the Tweet but now we have to perform the updating logic and after updating we also want to share the Tweet again right so that this retweet appears now here there's also another thing to be done which is updating the Tweet model here we want to add two important fields we want to add a field called final string retweeted by so who whom was this tweet retweeted by so we'll have required this dot retweeted by then we'll have string retweeted by sorry but it tweeted by let's copy this field so that we don't make any error then we'll pass it away so to be retweeted by retweeted bias not null then we want this dot retweeted by then we add it over here as well result dot add all retweeted by in a string should be equal to retweeted by then we'll have retweeted by map retweeted by otherwise an empty string we'll also add it to the tostring function retweeted by is dollar retreated by we'll add it to our equally equal to operator retweeted other dot retweeted by is equal equal to retweeted by and finally over here retweeted by dot hash code to be added now if you click over here and again try to generate the data class it will work for you no doubt about that but again you will get the idea over here like a normal ID we want it to be slash dollar ID so make sure you have that okay now coming back to this tweet is equal to Tweet now what we want to do is update the field over here not the likes part but the retweeted part so now initially the Tweet wasn't retweeted by anyone now it is retweeted by current user dot name so this is the guy who retweeted also here in our share image tweet and a shared text tweet we get this error because we made it a compulsory field to be added so of course we'll have to add it over here as well but when there is no retweeted by so basically it is our own original tweet it is going to be empty and later on in our UI we will check if retweeted by dot is empty so if it is empty we don't want to display anything but if it is not empty there's some username then we will show that this was a retweeter tweet now we'll again put it here now we can go right at the top where our reshare tweeters and here what we want to do is set likes to an empty field so since this tweet is getting reshared we want to set the likes to an empty field the comment ID should be empty field because we don't want any comments or likes to be present now and the reshare count should be tweet dot reshare count plus one so the new reshare count is going to be the old reshare count plus one now we'll update the reshare count and send it across then we'll have rest dot fold in case of any error we want to show snack bar saying l dot message and in case of any success which is r we have to do one more task so we'll pass this as async right now we just updated the original tweets reshare count correct so we have updated its reshare count now we want to create a new tweet saying that this tweet was created and retweeted by so earlier when we added retweeted by likes and comment IDs they were not required when we were doing this part I just added them so that I don't have to do it over here here what I want to do is just have final rest 2 equal to await underscore tweet API dot share tweet so I want to share the tweet with this but of course I have to make one more chain your Tweet should be equal to tweet.copy with and I want to update the ID of the Tweet correct so the ID is going to be ID dot unique we are going to take this from upright only and the reshare count should be zero here we have updated the reshare count now we are again putting it back to zero after this updated reshare count function has been called and we are setting ID to a unique ID because earlier what we did was use the idea where we use the reshare account so this was original tweets ID and reshare comp now since we are creating a new tweet and a new ID on its own we need to update these fields so basically all of these three Fields weren't even needed here they can be put here but I just wanted to show that you can also put it over here it doesn't matter because the only things that are being called in update reshare count are the D share count and the tweet.id so we cannot update the ID over here as ID dot unique okay you have to do it right below after this function is called great now after all of this is done we can just average two dot fold in case of any error show the snack bar with l dot message and in case of right we don't have to do anything as of now now reset read functionality has been created I'll go to the postcard or the Tweet card and here where I have my retreat button I'm just going to call ref dot read tweet controller provider.notifier dot reshare tweet I'll pass in the Tweet the current user the build context and then get done don't use user over here otherwise it won't work for you it will actually give a very weird thing and you won't understand why I would recommend you to always use good names over here not just user and current user something more appropriate but it serves my understanding anyways now that you have this done let's restart now here I'll try to reshare a tweet actually once the reshare has been done here let's just say show snack bar tweeter so what we have done over here is updated the reshare count on the original tweet and we have shared the Tweet again so that it appears on Opera file now if I click on one of this I'll click on hello you can see we are getting invalid document structure because we have added a new tweet I always forget to do this thanks to the error messages they always tell you the right thing so now I just want to add a new attribute called retweeted by which is going to be a string with size let's say 255 required create now I can restart and since we're getting this error I can't seem to resolve it to be honest so I can just delete all the fields let's just delete every single thing so I can have my database empty now I'll restart my app this is all empty I can just type hey over here I click on tweet I have this I can click on like so like is there I can click on retweet and the retweet has taken place and if I like it and then retweet you can see there is retweet happening the original likes are maintained new tweets are being created and they show up real time because of our app right real time configuration and logic but the counter is not updated on the tweets you are retweeting but if we restart the counter is being updated you can see one is over there one is over here that means it is updating in apparately we want to update at your real time and another problem that I have is retweeted by not showing up so I want these two things to happen first we'll work on the Tweet card where we will add the retweet part so you can see there we have added a comment of retweeted we will replace this with our own retweeted by and here again we are going to have a row and in this row we are going to have children and the first child in this is SVG picture dot asset where we show the retweet icon so we have asset constants dot retweet icon color will be palette dot gray color and the height will be 20. we'll increase it from the normal height after this we will leave some width so we have constant sized box of width let's say 2 and then we are going to have a text saying that this guy retweeted so here we'll have dollar tweet dot rate tweeted by and you have to put all of this in a string because you want to type this username guy has retweeted and now you can see we are getting all of this but there are some problems this retweeted shows up even for the people who have not retweeted so here we'll just add if tweet dot is retweeted or the retweeted by sorry is not empty so if this is not empty only then we want to show this otherwise just remove this and this doesn't show up for this time now the next issue I have is the font size so let's increase it so we'll have style constant textile where the color will be colors or palette dot gray color font size will be improved to 16 and font weight will be font weight dot w500 a little bit bolded so that you know it differentiates from the username below and this looks good so whenever we retweet it shows up now if I try to retweet something you can see retweeted he shows up test retweeted is also there but now we want to update the counter over here in real time why is it not being updated even though we have something present in the Tweet list right we have added the create trigger but that's the problem we have added the create trigger it doesn't listen for the update trigger we have updated the like count we have updated the retweet count correct so here we'll just have an else block so else or else if else if the data dot events so let me just copy this correctly else if data.events.contains databases dot star all of this but this should be update so if this is updating then what do we want to do so to update what do we want to do in case of create we directly insert it but in case of updating we basically want to get the ID of the Tweet we want to remove that tweet and then we want to replace it with the updated tweet so for that we need the Tweet ID we need the index of the tweet in this tweets array and then we want to update it okay so this should be fairly straightforward first we want to get ID of tweet so to get ID of the Tweet we can just have final tweet let's call this variable tweet equal to and we can just have tweet Dot from map and then we'll pass in data dot payload and now tweet ID will be final tweet ID which is equal to tweet dot ID this is final because its value is never going to change after this but this is variable because later on we're going to replace this this is the old tweet correct this is a new tweet sorry this is a new tweet so we're going to update it so anyways now that we have tweet ID with us what we need to do is find the index of the tweet in this tweets array so now what we are going to do is find the Tweet so we have tweet equal to and that's why we have put variable we are going to change this value right now this is updated value again we are going to set it to update value but right now we are not creating another variable you can create another variable to not cause confusion but here I'm just using this variable so now Tweed is going to be equal to tweets dot where and where do we want to get like which where do we want to get which tweet do you want to get so we just wanted to eat where element.id should be equal to tweet ID okay so you want to get a tweet in this tweet list where the element.id we are looping through it essentially so we want to get element.id equal to tweet ID which is this ID so in the tweets list we'll get the tweet and then we'll just call First on it because we know there's only going to be one tweet with this particular tweet ID correct now that we have got the street we just want to remove this tweet but even before removing we need the Tweet index so that we can insert our updated tweet into that tweet's position so we have final tweet index is equal to tweets dot index off and then we pass in the tree so this is a tweet now that we have stored the Tweet index we have this tweet ID now we can just do tweet dot remove where element dot ID is equal equal to tweet ID so we have removed the old Tweet now so this removes the old Tweet now we just want to insert the updated Tweet now to get the updated tweet and insert it it's going to be very simple for us we just want to do tweets dot insert at tweet index and that's why we add store tweet index earlier because after we remove the tweet and then find tweet index like this so if we do this much right if we do this much we won't get the Tweet index because we have already removed it if you have removed a tweet and then find the index of that tweet will we get any index no that's why we want this logic to be above this and we've got the Tweet ID over here so that we could get that particular tweet we are getting the Tweet by ID essentially over here and now we are inserting a tweet index the element which is tweet but this tweet is the old tweet itself right so now we want to update the Tweet Again by doing this tweet is equal to tweet Dot from map now I know this is a lot of logic so I would recommend you to pause it go through it on your own I'll do one dry run after this after we get to know that it's working if it's working then I'll do a dry run so if you want to follow along you can follow along but I would highly recommend you to use your own logic to understand this now we'll restart the app and after restarting it let's try to retweet and I just realized the error in our application even if you try to retreat the retweet count won't upgrade and that's because the tweet.id that you're getting here is the updated tweets ID and the updated tweets ID and the old tweets ID on the same thing right we had added that logic on our own and we forgot about it so now how do I get the ID of the tweet so now if you try to print latest let's just call it data dot events at zero so now if you restart your application click on retweet over here you'll see over here this is the event now this is the document ID to get the document ID what we need to do is get this thing so to get this thing we can just find this full stop at the last so you want to get index of this full stop so let's just get it this is not the Tweet ID we had made a mistake so let's just get rid of it to remove the error we can just do final tweet as equal to this to get the Tweet ID now we are just going to have first of all the starting point or the starting index and this is going to be latest data dot events at 0 dot last index off and we want to get last index of this documents Dot so let's have documents Dot so we'll get the starting point now to get the ending point we want to get last index of dot update right so now we can just repeat this and have final end Point equal to dot update okay now we want to get the Tweet ID so we'll have final tweet ID is equal to latest data dot events at 0 Dot substring so we have the starting point we have the ending point so we want to get a string from the starting point to the ending point done but this is not it because starting point is last index of this will also consist documents dot we don't want it to consist of documents dot right we want to remove that so how can we do that well we can just calculate the number of characters in documents dot which is 10 and we can add it over here so starting point doesn't start from documents dot it will ignore them it will do starting point plus 10 ignoring documents dot which is 10 characters long till the end point dot update won't be used in the end point this is because it doesn't contain dot update our index of is still here only so now we'll get this ID and now based on this everything will get updated and of course we are getting this error so we want to convert it to a tweet variable sorry if we convert it to a variable we can use it later on to reassign so now what we have done is get ID aware of the original tweet see we got the ID of the original tweet we are finding that element by using element.id is equal to tweet ID then we are getting the Tweet index before removing the Tweet then we finally remove the tweet get the new data so get the new latest data and insert it at the particular tweet index and at a particular Tweet now we'll restart the entire thing I've retweeted many times here just to test so just to reduce complexity what I've done is just deleted all the tweets now I'm going to come here I'm just going to type a new tweet new tweet and then click on Tweet now another problem that I face right now while retweeting is that whenever I tweet both the dates are the same thing we don't want both the dates to be the same thing whenever we retweet we want to update the date as well so here we can also update the date by just having tweeted at with the date time as date time dot now so the tweeted ad is now updated now we can just go and restart the app now if I try to retweet it's over here there is an update if I retweet again it's now 2 and it shows up right at the top now if I restart the application this configuration doesn't change so now finally our retweet is also working the earlier logic did not work because of the new tweet ID that we were getting we need to get the ID of original tweet I hope that is clear if it's not I would recommend you to go through this I'll I've already gone through gone through the dry run we've got the starting point we have gone got the ending point by index of now we are substring them so that we can get a particular section of the string then we are getting the tweet the original tweet we are getting its index before removing it and then we later on remove it and then we are just having tweet.form map and inserting it easy so the retweeting part is also done and it is working real time if I also try to like or dislike it also works the next feature we want to work on is whenever I click away I want to go to the new screen which is the replying screen or the comment screen whatever you want to call it and the specialty of this replying feature is that whenever we reply this is going to be there in the comment section of this tweet but it's also going to be there on our feed because we are replying to some person so it is basically our tweet that is present in other persons tweet so this is a really cool thing to work on so let's get started so we'll start off by creating a reply screen so we are going to go in the Tweet folder in the views we are going to create a Twitter reply screen or review whatever you want to call it dot dot and here we will go into import material dot we are going to create a stateless consumer widget and we are going to call this not stateful we are going to get State less consumer and we are going to call this Twitter reply screen this is nothing else but just a simple reply screen and now you might think that yeah if this is a reply screen this is going to have text editing controller and I said if you have text editing controller we need to use stateful consumer and you're right but we are not going to have text editing controller we are simply going to use the on submitted property in the text field anyways here in the app bar we want a very simple thing to show up which is a title saying text that this is a tweet and this is how the original one looks as well now in the body we are going to have a column widget and in that column we are going to have children and the children the first child we want is a tweet card so for the Tweet we are going to have a final tweet tweet over here and then we are going to require this through the Constructor so we're going to have required this dot tweet so first we want the original tweeted B displayed and then in the list view we want a list of reply tweets to show up okay so now let's see how this is looking so we are just going to create a static material route function so let's go over to the create tweet view grab the route thing over here and paste it away up now we need to import not import we just want Twitter reply screen to show up over here but this requires a tweet property so we need to pass in a tweet property and this tweet property will get it from here so we have to it tweet and then we'll pass it over here sweet now just to see this I'm just going to go to the create tweet view I'm going to wrap not create video sorry we are going to go to the Tweet card and what I'm going to do here is just wrap the entire column widget with a gesture detector widget so whenever we click over here we want to go to the Twitter reply view screen so we have Navigator dot push and then we are going to the Twitter reply screen dot route and then we pass in the particular tweet and we get this tweet from here through the Constructor great now we can restart the entire app now if I go here click over this tweet we are in another screen and I can see the Tweet over here now the next thing I want is first of all I want to be able to write a tweet reply right so now to get a tweet reply I'm just going to use the bottom navigation bar property on this scaffold and then I'm going to use the text Field property and this text Field property just needs to add a decoration of input decoration and there should only be a hint text which is tweet your reply that's easy and here it is it shows up pretty cool that's the only decoration we need and now we need the unsubmitted property so we get a value this is going to be const obviously and whenever it is submitted that means whenever we type something over here and click on enter what do we want to do well we just want to submit this tweet like a normal tweet right so we can just use ref dot read tweet controller provider dot Notifier Dot and let's see what tweet we use what function we used to share a tweet and it was called share tweet so we can just add that what are the images no images what are the text well the text is the value that you are getting from your from the on sub method then we pass in the build context and that's all we are not adding images property over here so you can add a bunch of options down below the text field but I'm not going to do any of those the reason for that is I've already covered this so I don't want to make this video any longer I've already covered this in the create tweet view part so you can just copy the logic and if you've understood it I would recommend you to retype it and try it on your own and now what do we want to show now I want to show all the replies but wait is that all that we need in the share tweet logic because we are saying that we want to share a tweet but nowhere are we specifying that this is in response to this tweet so how can we list them over here correct it just knows that it is a tweet sent by the current user that means us with no images text is there and if case of error it's going to show us a scaffold or a snack bar but nowhere does it know that it doesn't reply to this tweet so what we need to do is in the shared tweet we need to add some logic and we have to go down into every function the share tweet all of those function and here we have to require one field which is required string replied to so whom are we replying to we'll copy this and put this in the share image tweet as well so if you are replying to anyone we need their tweet ID this is not the user ID this is a tweet ID because we are replying to this tweet yes we are replying to this user but user can have many tweets we are replying to this tweet ID of the user so you want to store the reply to will be the Tweet ID of the user basically whatever tweet the user posts that ID so in the Tweet model we'll have to add another one which is final string replied to ID or applied to now I'll get this through the Constructor so we have required this dot replied to and now I can generate the entire data class I'll remove the two Json from Json functions I'll remove dot convert I'll fix all of these issues like the street type shouldn't be a map it should be two tweet type DOT type and this should be tweetype removed we'll treat this as a very simple string and convert this to a tweet typing also here the ID should be slash dollar ID don't forget that okay so now we are getting a bunch of Errors so let's go there in the Tweet controller we need to add the reply to property we will add that because we have just now got it from the parameter we'll do the same in the share text tweet we're going to add reply to replied to and I think we've not added that over here so let's quickly grab it and paste it we also need to mention replied to over here so we'll pass that in and also yeah also here we have to pass in the reply to so everywhere we need to pass and reply to and take it from the parameter now we're getting this error in Twitter reply view so we need to go there and we need to tell it that this share tweet has a reply to correct we are in the Twitter reply view so definitely it has a reply to and what is it reply to well I said it is going to be the Tweet ID so we'll just use tweet dot ID don't use tweet.uid used tweet.id this is a tweets ID tweet.uid is the person ID who posted this tweet in the create wheat view also you have to go here we have to add replied to property but this is going to be empty because you're not replying to anyone this is a create tweet View and we are going to reply to no one this is our original tweet just like that so this looks good now I can just tweet my reply I'll just say how are you doing and I'll click on enter you can see invalid document structure unknown attribute ID there is one problem here in the tweets we need to add a new attribute called reply to don't forget that string 255 required create and just so that there is no confusion I'll just delete every document that's present now everything is gone I'll just type hey guys and let me just beautify this further and I'll click on tweet here you can see invalid document structure unknown attribute ID so this is a problem with our tweet model we have sent to map but we don't want to map to be there the ID of two map so remove that that's a mistake I made now let's restart the application and see so I'll just say hey guys again and it should work this time so we'll go on tweet and here it is now I'll go over here I want to reply so I can just type doing good and then click on enter now just to verify this is working I'll do Ctrl R and we are having doing good aware but let's see if it applied to it's working and yep it does work now let's just compare the IDS of these two tweets so this was the ID and let's see the ID of this one it's the exact same thing so we have successfully achieved what we wanted to achieve now the next part is displaying all of those tweets that are in reply to this particular tweet so we'll go back to the Tweet API and here we are going to add a new future and we are going to call this future list of document and since we have used future you know what's coming future provider and we want to get replies to a certain tweet so we'll just have get replies to tweet and here we are also going to ask for the Tweet information because you want the tweets ID so what tweets replies do we want to get that's what we are asking here we can do that by doing final document is equal to await so we need this to be asynchronous and then underscore DB dot less documents we have already seen if you want to get a bunch of documents we can just list them and then we'll mention the database ID so we have upright constants dot database ID app right constants dot tweet collection because you want to go in the Tweet collection now and now it will just list all the tweets that are present in the database correct but we don't want that we want all the tweets which are in reply to this particular tweet and if we go to some other tweet we want all the tweets and reply to that tweet so if we have to think about it in programming terms if this is a tweet we want to get reply to tweets which have their reply to property as this because earlier if you saw if we go to the tweet controller you can see the reply to property year was the tweets ID so we want to get all the tweets which have the ID the same as the reply to property so here how can we do that well let's see if there is anything there's nothing except queries so your queries is going to help us queries will may help us select certain documents from here here we used queries because we wanted our data to be behaving this differently we wanted certain data but we did not have access to them based on this we had certain limitations through which we had to do this or you can think about it like filters we had certain filters According to which we wanted to have our data presented to us so here we are going to use queries and here our query is going to be query dot equal so we want to get all the queries or all the documents where the reply to property is equal to the Tweet dot ID simple so here we are just saying list all the documents where query is equal to the replied to property and the reply to property is equal to tweet.id I hope that's simple enough to digest I'll repeat it once more we want to list all the documents in the tweets collection where they replied to property is equal to the tweet.id property okay now we can just return this document so we have a return document dot documents so this will give us a list of documents now we can go in the Tweet controller we can create a future list of tweet document or return data type of the function and we are going to say get replies to tweet and here we just want to get tweet from the parameter and here the job is very simple we just want to convert let's just put this function up here so I'll put it right over here and now the task is very simple we just want to get something so we have final document is equal to a weight so this will be asynchronous underscore tweet API dot get replies to tweets okay now we have gotten replies and the documents now we just need to convert it in a format of tweet and we've covered this logic earlier we have done this before for get tweets function get tweets is basically like get replies to tweets only difference is that it gets all the tweets and get replies to tweet filter something and gets us the tweets so we can just put it here I can do documents dot map tweet and convert it to a list all of this I hope this logic is clear to you if it's not let me know in the comment section I'll make sure to answer you now I can just go up right at the top and create another future provider which is very similar to get tweets provider so I'll just copy it and we have get replies to tweets provider then we have future provider dot family we need a tweet so we have tweet tweet and whenever we use family we want the data type to be present here as immutable so let's go right here this is immutable ready God and here we will watch the Tweet controller provider and we'll get get replies to tweets and then we'll pass on this tweet if you remember what family is we are going to accept this from our UI file so we can go to our Twitter reply View right here and let's just copy all of the logic that we had in the Tweet list let's just remove the print calls let's copy everything that's mentioned here it's the exact same thing we are going to need let's import the common dot dot file save it most of our errors are gone import upright constants even more error are gone now let's make some modifications here we are doing ref.watch get tweets provider we don't want all the tweets over here right we want get replies to tweets provider and it's giving us an error because this is a future provider family whenever it's family we have to treat this like a function and then pass in what it's requiring a tweet so let's pass in the tweet and the Tweet is exactly this thing okay now we have got replied to tweet dot when data and whenever we get the tweets we have to show this in a format of tweet card in a list view Builder perfect exactly what we want and all of this is real time all of the logic to make it real time if you remove this it will still work but it will not be real time we want everything to be real time so all of this is now done let's restart the application I'll go over here not available the attribute here is replied to let's just say ascending or descending order whatever you want I'll just type descending and click on create now I can restart the application go to hey guys and nothing shows up but our error now goes away and now if you open the terminal you see this is the error this is UI related error basically we have a list view Builder over here and we are also having a tweet card in a column less view Builder has a tendency of taking the entire screen it's not getting the entire screen so together the entire screen we have to wrap it with the expanded widget it doesn't give you the exactly you know the entire screen but it gives you all the available space and this should work so let's restart our application go to hey guys and if you open the terminal it's still giving us an error because we are at the loading part if we are at the loading part we have to wrap here also with expanded widget because basically this widget is now returning list view Builder from here it's not expanded so UI doesn't know anyways let's restart the application go to hey guys and we are having doing good over here just to test the logic if it's correct or wrong let's tweet another thing publicly so we have high I'll just do this much click on tweet and we are having this over here but if I go to hey guys hi shows up here as well why is that so so if I refresh the upright console and go to documents you'll see highest there replied to is still empty but even then it's showing up over here that's a weird Behavior right now if I go back go to doing good I have high showing up here as well and if I go to over here it's showing up here as well that's the thing this is how apprite works this data now has some value in it so if you try to print data it will print you the data every time you go to a new screen you can see right now it has two highs now if I refresh this it has three highs so it's continuously rebuilding and giving you new Highs but if you restart your entire app and then go to hey guys High doesn't show up so we need to do something that we check that if the Tweet here is already mentioned in this part we don't have to add it and we also have to check if this replied to of this is equal to the ID of this tweet then we should only put it why am I saying these two conditions this is because every time we create a widget new tweet appears whenever we click over here the Tweet keeps on appearing here even though it's not replied a part of the reply to right so you want to check if the replied to of this tweet is equal to the ID of this tweet so if I replied two of this tweet is equal to the ID of this tweet that means it belongs here and if it doesn't then it doesn't belong here right so let's add that logic your before the if condition over here we are just going to check okay first we need to convert it to a tweet modded so we'll have latest tweet final latest tweet don't name a tweet otherwise you'll get confused with what's mentioned in the Constructor final latest tweet is equal to tweet Dot from map and we have to pass in data.payload if we do this we get the latest tweet in a tweet model format then I check if latest tweet dot reply to is equally equal to tweet dot ID that means the reply two of the latest tweet that means this ID this replied to of this tweet is equal to the ID of this main tweet only then do we have to run all of this logic so you can just put all of this logic inside this and if it doesn't equal then don't execute any of this logic don't have to insert anything don't have to do anything okay now if I restart my application and try to see if it's working I'll go to the hey guys I'll type this hello and click on done I'm getting hello over here that's good I'm getting hello over here as well now if I still try to do um and then click on tweet and if I go to Hello it doesn't show up Let's test it one more time if I do nice over here I get nice I'll go back come back over here I get nice two times if I go back come back I get nice one more time so basically this logic is working the reply to is equal to tweet ID so right now my data consists of nice and if it consists of nice tweet latest Tweed dot reply to is equal to tweet.id so it's equal right so it's again rerunning this entire thing so it's seeing that yeah if all of this is done then I can just you know have my nice tweet again here now to avoid this many nice coming over here what I can do is add one more condition I want to check if the nice tweet already exists over here or not if it already exists over here then I don't want to add it again but if it does not exist then I want to add it so here we are going to be running a very simple for Loop so we are going to have Boolean is tweet already present since the Tweet is already present then we don't have to execute all of this initially it will be false and then we are going to run a for each Loop or a foreign Loop we are going to have four final tweet model in tweet tweets not tweet tweet model I've named it because tweet is already there latest tweet is over here so this is tweet model then I want to check if tweet model dot ID is equal to latest tweet model dot ID so I'm comparing both of their IDs I'm just seeing if the latest tweet has the Loops tweet model already present so if their ID is match that means it is already present so is tweet already present is equal to true and then I want to break it so that it doesn't Loop through more and more elements we've already found our answer okay so we are just checking through every tweet and tweets so it we are checking through every reply if the Tweet is already present and if the Tweet is present we are checking that by that ID we are just doing if tweet already present is equal to true and then break off because we've already found our answer that yeah it is present so why should we run more for Loops or more iterations and here we are checking if if tweet is already present and and latest tweet.replied to is equal to tweet ID right no if tweet is not already present then we want to execute all of this if tweet is already present why would we execute it it's the same thing as what we are seeing over here we don't want this so if tweet is not present and latest tweet dot reply to is equal to tweet ID then we want to execute all of this now it should get rid of all of the errors so if I now type your nice go back and you know come back nice is there only one time this is good now if I come over here this has no comments this has no comments even this has no comments that means the reply to feature is also over but yeah there is one thing left whenever we are replying to someone we wanted to show in the Tweet so we can go to our tweet card and we'll scroll down right below the text result the reply to we have added a comment and here we are going to check if tweet.replied to dot is not empty so if it is not empty then we want to display that we are applying to this particular user so we are going to return a rich text and the text is going to contain a text span because we want to show a white or a gray along with a blue one right the username of the user should be colored in blue now in the text pan we are going to have text which is going to say replying to then a style of constant textile you can select white or gray I think gray would be better because we don't want to focus on this text as much as the main text then the font size should be 16. then in the children we need another tech span so we have text pan and here we are going to add the rate and the name of the user now how do we get the name of the user we don't have access to it if you try to do it let's see if you get it you know tweet dot reply to this is the Tweet ID that we are applying to it this is not the name of the user so how do we get the name of the user for that we need the uid of the user that is also not mentioned where the reply to user ID is not there so what else can we do well we have to create a new provider which is basically getting tweet by ID so we get that particular tweet then we take its uid and then use the user details provider and then we can get the name of the user so let's do that we are going to go to the Tweet API now right at the top we are going to Define future document get tweet by ID and obviously since you're getting my ID we need a string ID now we can create one missing override we can have async over here and we want to return underscore DB dot get document we want a single document because getting a tweet by ID a tweet is only going to have one document or one ID so we will get one particular ID and we are going to use apprite constants dot database ID app right constants Dot collection ID or tweets collection and the document ID document ID is the ID that we are getting from the parameter okay now we can go to the Tweet controller here we are going to Define our get tweet by ID function so let's do that over here we're going to have future tweet get tweet by ID then we are going to get a sink over here then we are going to get ID from the UI file itself so we're going to have this then you're going to have final tweet is equal to underscore tweet API Dot get tweet by ID then pass in the ID then we are going to have return tweet Dot from map and this is going to be tweet Dot and there's nothing like it so you want to do await now we have document earlier it was future document and now we want to get tweet.data so we have converted it into a model and returned it and now finally we just need a simple future provider so we can just have future provider and we'll name this get tweet by ID provider we're not going to have anything else other than family because we want a string ID we also need the Tweet controller so you just copy pasting stuff now we have covered a lot so just get a hang of this we are getting 3D controller we are converting it to our models we are sending data to app right we are getting data from upright all of the same stuff and now we want to get Tweed by ID and we'll pass in the particular ID also your product semicolon now we can go to the Tweet card and here we are going to wrap everything by ref so we are going to have ref.watch get Tweed by ID provider we'll pass in the ID the ID is tweet dot reply to so we want to get the Tweet ID or the Tweet by ID of tweet.reply to which is the ID of the tweet that we are replying to dot when and whenever we get the data we have to do something so when there's data we have to do something when we have to do error or St we have to do something and if you have loading we have to do something so in case of the loading we just want to show a size box so we can a sized box in case of error we want to show the error text so let's have error text and we'll have error.2 string now I'll take the rich text and here we are going to return that rich text and here we are getting this error we just need to add a parenthesis here before the bracket so yes now we have the data but what is this data this is the replied to data or applied to tweet this is not our original tweet this is a reply to Tweet now based on this we want to get the name of the user right now we get the uid of the user to whom we are applying by this so how do we get the name of the user so to get that what you're going to do is final replying to user which is equal to ref.watch replied to tweet.uid and not this sorry what is the provider that we want to have we are going to have user details provider then we are going to have replied to tweet.uid so basically we have rev dot watch we pass in the user details provided the reusable provider we created remember right here you have used that in the current user account provider as well not aware sorry we have used it in current user details provider now that we have replying to user with us now we can get their name but before that we need to have value because right here this thing is a user model now earlier if we didn't use value it would be a future provider thing an async value okay so let's get replying to user put it right here replying to user dot name make sure to use question mark aware instead of exclamation mark because when you use exclamation mark you're saying that this value cannot be null but for some time for even a second this value can be null when it's trying to get the user details okay so save this restart your app come aware and you see replying to at the rate test this is good now here I want to change the color to blue color and I want to leave some space so that this sticking doesn't happen I'll save it and here we get it replying to at the rate test so you can see everything is replying to test over here this looks good now let's just try to retweet replying to and we get all of the features in one single tweet retweet replying to like and if you try to comment on this we can also comment okay great now I think all the features related to tweet are now completed now the next step is to go away or Implement a search screen basically we want a text field away up and whenever we search over here we want to get a list of user profiles so let's get started with it right now so what I'm going to do here is just close all the save files close the Tweet folder and create a new folder called explore and here I'm going to create a new view called exploreview.dot and after I've created it I'm just going to import material dot create a stateful consumer widget I've created stateful consumer because my app bar is going to have a search field and we'll be requiring text field controller for it so let's have explore view right here import Front River pod we are going to return a scaffold and here I'm just going to exp take explore view go to UI constants pass it right here and I think this should show up yep it does now what I want to do is add an app bar over here but if I add an app bar it will be right below this so I want to eliminate this app bar which is present in the home screen so in the home view if you see we are adding an app bar over here what I want to do is if underscore page is equal equal to 0 then I want it to be app bar otherwise null so only for the page 0 will this app bar show up otherwise it will not be there so if you go there there's a bar but if you go over here there's no app bar easy now we can go to the explore page have app bar pass in the app bar which will have a title and the title is going to be sized box of height 50. then we need a child for text feed we have passed the size box of height 50 because text field might exceed this length so we are restraining or constraining it to just a particular height of 50. now in the text field I'm going to pass in my controller so I have to create my controller I'll create it right here final search controller is equal to text editing controller let's have text editing controller now I want to dispose the source so I'll have search controller dot dispose and I'll take the search controller and put it right here now if I see your way up here it is my search field but I want to style this even more so I'm just going to pass in a decoration of input decoration and here I'm just going to have first of all a fill color and my fill color is going to be palette dot search bar color with filled set to true so I'll just have filled true after I have this and if I go here this is color which is pretty good now I want to enable borders so that I can move this border and add my own border so here I'm going to have enabled border so in the enabled border I want outline input border with border radius and Border radius is going to be border radius dot circular 50. after that we need a Border Side and Border Side will be constant Border Side basically we want the normal text field to be a bit rounded should have no outline underline border so I'll just pass this as color palette dot search bar color and of course for the Border radius we have this now we won't be able to see over here because this is focused so I'll do the same for focused border and now it's going to be the exact same thing so I can just extract this out put it here and call this app bar text field border which is equal to this thing now I can copy it paste it right over here paste it for the focus border as well save it and here you can see this is curved exactly like the Twitter thing now I want thin text to show up so in the hand text wire I'm going to pass in search Twitter save it again here it is now I want content padding to be there because I want to shift my text from here to somewhere a little bit down and to a little bit more right so in the decoration I'm going to have content padding constant Edge in such dot all 10 dot copy web left 20. basically from the top I want 10 padding and from the left hand side I want 20 so that I can go to the right hand side and here it is looks great so this was about designing the search field now we want to be able to search for users so for that we are going to go to the explore explore folder create a controller and call this explorecontroller.dot then I'll have a state Notifier and a state Notifier provider so the state Notifier is going to be explore controller let's remove Notifier from here then we will need a straight Notifier a Boolean value and false because this shows it's loading so it's loading as initially it falls and here we are just going to have a future list of user model to show up for search user of course we are going to create their API but right now I'm just giving you a clue of what's going to happen we're going to get the name of the user whatever the user types in wire we get the name and based on that we search in app right and the list we get we have to display it in a future provider okay so now let's go ahead in the user API because this is related to user user searching so we're going to go to the user API and add our new function which is going to return a list of documents and we're going to call this search user by name and here we'll get access to the name of the user now I'll create one missing override I'm going to have async over here then I'm going to copy all of this paste it down and going to say list document actually I'm not going to return this I'm just going to save it in documents just like we have done before for other things so we are going to list the documents we are going to go to the user collection and here we are going to add our queries you remember the queries and here we are basically going to search and there is an inbuilt query search provided to us which is query dot search so if we use this we should be able to search for a specific value and was it what is it that we are trying to search which is name and we'll pass in the name through the parameter now we just need to be able to return it so we'll have return documents dot documents we don't have that option we are getting this because you have not awaited this so let's await it take this documents and return it documents.documents now we can go to the explore controller again and here we have to import the user API so we have final user API underscore user API let's require this so we have required user API user API and then we have underscore user API is equal to user API now we can take this and have user API dot search user by name we'll pass in the name and this should be equal to final users is equal to await this so now that we have list of document with us we need to map through it and convert it into a user model so that we can return a list of user models so we have return users dot map now we have e with the help of this we are going to return user model Dot from map e.data dot to list we have already looked at this logic before in the Tweet controller we have done this for get tweets and get replies to tweets functions mapping through all the users returning one particular user model and converting it to a list and this happens for literally all the users that we find now we need to create two things a state Notifier provider for our explore controller so via explore controller provider and now we want to return explore controller and here we need to pass in the user apis which is ref.watch user API provider and the next thing we want to create is future provider and the future provider is going to be called search user provider because you want to search the user dot family and here we are going to get the query from the UI file so basically whatever you don't find the way up you can just take it from family but in the family you can just import one thing you cannot have two or three things okay now we can return this but before that we need explore controller so we have explore controller final explore controller equal to rev dot watch explore controller provider dot Notifier now we can use this explore controller and return it so we have returned explore controller Dot search user pass in the name from the parameter here and return it now to display the correct thing we can go in the scaffold in the outside the app bar in the body outside that bar I said so body and here we are going to use the future provider now we know the syntax search user provider then we'll pass in since it's a family future provider we have to use this as a function and then we can do searchcontroller dot text this is the search controller that we have as a text editing controller and is bound to the text field so we are getting text from it dot when and whenever we get the data we get users in case of error we know already what to do error St will return something in case of loading you have to load a loader so we have constant loaders showing up here next thing is error St so here I want to return an error text and then I'll have error.2 string so here I have users list of user model and then I want to return a list view build up okay so I can just return list view Builder because this is a list I want to return it and then I can have users.link now finally I want final user equal to users at a particular index I can take this user return it in a search Style which I'll have to create basically this search tile is going to consist of everything about the user like their Avatar their number of followers following all of that but we only want to return an avatar the username their bio their add the rate username okay so we can go here in the explore create a new folder for it called widgets and here we are going to have search I'll import material dot I'll create a stateless widget and call this search tile we'll be requiring the user model so we have final user model user model and then we are going to require this through the user model Constructor now we have to return a list tile so we can have return list Style then we are going to have leading which is circle Avatar and then we need a background image which will be Network image and we'll pass in the user model dot profile picture okay then we need a radius of 30 so that it looks big now just to see how it's looking we can return it over here so we have search tile we'll pass in the user model which is the user we have extracted all of this pretty similar to what we have done earlier now we can restart our entire application now we can restart the entire application go to the search bar here you can see we are getting error because we are not finding uh an index so let's create an index here in the tweets not in the tweets actually we have to go to the users collection because we are having a query on users collection not the tweets collection so we'll create index let's call this search user name then this is going to be of the type full text since we are searching the user it's going to be of the type full text even if you mess things up it will give you an upright exception over a that this cannot be of the type this you have to use full text or whatever and then you can change it accordingly or you can just read the docs to get a clearer idea so I'll pass in name I'll pass in descending I'll click on create so I've passed in an invalid key I want to pass in searching that's it nothing else and then I'll have full text I'll pass in name ascending or descending whatever then click on create index has been created restart the application go to the search no error now I'll just have hi click on enter nothing shows up if I do test click on enter nothing shows up that's weird because my email steps are there at gmail.com so now to make this work we need one last thing over here in the explore screen there is a possibility of many API calls going over here in the body so what I want to do is is show users should be false so as long as it is false we should not be able to show the users list only when it show users is true we should show this otherwise we should only show a constant size box okay and this issue size box will be true whenever on submitted is set to true so whenever on submitted is clicked on we can do set state is show users is equal to true great now we can restart the app we can search for a user with test click on done and here it is here shows up the user with their profile picture now let's add more things to this so we can go to the search tile and here after the leading we need a title where we want to show the user's name so we have user model dot name then we need a style so that you know this looks bigger and we have textile where the font size should be bigger than original font weight should be a bit Bolder not exactly bold so we'll have font weight dot w 600 we'll save it and here it shows up in the subtitle we have a column and in the column we have children in the children we have a text so the text is going to be this we'll paste it right here it will be usermodel.name we'll put add the rate before it and we have to interpolate this so basically adding add the rate dollar so that this is a variable name with other rate before it then the font size can be 16 and we can remove the Bolding part and since it's a subtitle it's going to be of the gray color now we need another text just like this one so we'll paste it in and we'll have user model dot bio and here the color should be palette dot white color the bio should show up in the white color because the subtitle color is usually gray and here you can see we are getting at the rate test right here we don't want it here we want it to be here so in the column we can have cross access alignment as cross access alignment dot start and here it is now if there is any bio of the user it will show up here and if there is no bio it will not show up or like it is there but you cannot see it obviously because it's empty now the searching feature is also complete now the next feature here is going to be whenever we click on this user tile we should be able to go to the user's profile and there we get the option to see the user's Banner image their profile picture their followers following their recent tweets all of that cool stuff so let's close all of the save files close all of the features and gets and let's get ready for another feature which is the user underscore profile now we'll start off this user profile by creating a view of it like how it should look there are a lot of levels to use because in Twitter if you see there it is not just you know simple scrolling it has a weird scrolling effect so you want to give that effect so we are going to do exactly that so here we are going to create a views folder create user profile view import material Dot and now create a widget for it and now we are going to create a stateless widget for it and we are going to call this user profile view actually we need a consumer widget for it not stateless widgets so let's read rename it and here we are going to need a widget ref and we also need to return a scaffold and in the scaffold let me retype it we are going to have a body no app bar directly a body and in this body we are going to get the user data so directly we are going to return a user profile how are we going to return that because we are going to ask for that user model right over here so we're going to get the user model from here and display it accordingly so I can just have use a model user model Now to create a route for this I'm just going to go to some view file let's say home view I'll copy this route I'll go to the user profile view and just post it over here and then I'm going to return a user profile view but it's not going to be constant we have to return a user model so pass in the user model user model and we're going to take this from the parameter simple now based on this we are going to return the body as User it's not going to be user profile view sorry is going to be a new widget that we are going to create in this folder itself which is user profile just user profile it contains the main code for our user profile design so we are going to have import material Dot then we are going to have a stateless consumer widget called user profile then we are going to import consumer widget and then we are going to return a nested scroll View now we need a header sliver Builder we need a header body sorry not a header body just a header sliver Builder and a body so here we're going to get two things context and is in a box scrolled so after we get both of them we have to return something and in the case of body we also need to return something again so in case of heady header board self sliver Builder that you um you had you you would you could you do you would you want you you could do so you you do you could you you want you want thank you if I've heard of liver Builder we're going to have sliver well we have to return first and this requires a list of widgets to be returned so you're going to have a list of your return and then we're going to have sliver app bar and here I want to have an expanded height of let's say 150 floating should be true this means that the app bar is floating or the app bar should become visible as soon as the user Scrolls towards the app bar snap should be true this means that the floating app bar will snap into view and both of them should be true together or false together and then we need flexible Space by a flexible space because now this app bar is going to be used to show the banner picture of the user so we need a flexible space bar and now we are going to have stack because I want the user's profile picture to also be shown right above right on the top of this banner picture so first of all let's have banner picture and we are going to have positioned dot fill that means it takes the entire space and then in the child we are going to check if user Dot not user so we want to get the user picture here as well so you want to get final user model user model require it through the Constructor here when we return user profile will pass in the user which is the user model so here we have child as the user dot banner picture and we want to check if user.banner picture is empty so if it is empty then I want a container of blue color to show up that's what Twitter does if the user hasn't selected any banner picture it will just give a color of blue so we have palette dot blue color but if the container is not empty then what do I want to do well in that case I want to use image dot Network and here I'm going to return the banner picture so it's going to be user dot banner picture okay now we are getting this error because we have not specified children in the stack so let's pass that in take position dot fill and paste it over here and for the time being the Border body is going to be a simple container now we want to see this in action so what can we do we can go back to our search tile in the on top of this search tile we can just say navigator dot push context and user profile view dot route and then we'll pass in the user model okay so we're getting this user model based on the search screen whatever the user searches if you're getting that new user model you're passing it through the list Style on the on Tab now we are here from here we pass it to the user profile over here okay so now if I just click over here you can see this shows up very nice now what I want here is at the top over here I want the user Avatar to show up and here the profile picture not profile picture sorry your is the profile picture going to be here is a follow button this is going to have the name of the user at the rate name of the user followers following all of that stuff the bio of the user and then all the latest tweets done by the user so to do that well first of all I'll need your in the stack a circle Avatar I'll have a background image and the background image is going to be Network image and then I'll pass in user.profile picture I'll save it now I also need a radius and the radius is going to be let's say 45 I'll save it and here it is looks very weird I know now I can wrap this circle Avatar with a position widget so that it goes right below so we have bottom 0 and here it is so it has gone to the bottom of this flexible space right here that's exactly where we want it to be now next thing we need is a follow button which should show up right here so to do that we are going to have an outlined button because well we need an outline button and the child is going to be text which says follow now this text is going to depend if it's the user himself then it's going to be added profile but if it's other user it's going to be follow and if it's not the same person and if we are following the user then it's going to be the unfollow button but one thing is going to remain constant the textile which is going to have a color and the color is going to be palette dot white color and now when I put this button you can see again we get the similar design now to avoid this what we can do is wrap the outline button with a widget called container and here we are going to specify the alignment so the alignment is going to be alignment dot bottom right so if we do bottom right it will shift right to the bottom and I also need some padding basically margin so we can imagine or padding both will work in this case and then we are going to have agencies.all 20. now if we do this you can see it went away from the edges of the mobile so it's not going to be constant now you need to check if we want to show edit uh you know if the user is themselves so edit profile or someone else so we are going to get current user which is equal to ref dot watch current user details provider dot value now if current user is null so return current user is equally equal to null then we want a constant loader otherwise a nested scroll View and now we are going to take this current user put it over here and check if current user dot uid is equal to the user.uid current user Sr user user.uid is what we have taken from the Constructor if both of them are equal then we want edit profile to be there otherwise the follow button okay so we get the edit profile because it's our own User it's us now to add a different border to this to our outline button we can have Style elevated button dot style from and the shape will be shape rounded rectangle border where the Border radius is going to be border radius dot circular 20 and the padding is going to be constant Edge in such dot symmetric let's say in the horizontal Direction 25 basically we're going to add a little bit of padding from the sides and I have a circular border radius and to change its color we can just do side Border Side color palette dot white color now if I go way up I have this button showing up which is pretty cool and it is rounded as well now to increase the width we can just go ahead and type with let's say 1.5 10 but I don't want any web so I will remove it so here is our edit profile button now we need to get out of this this is all that we needed in this app bar on the banner pick I needed to show this profile picture and the edit profile button now below this we need to show the username of the user and all of that stuff so I'll just go to the sliver padding in the custom scroll view so after this lever app bar gets over I'm going to come here and have sliver padding basically I want to add a padding from all sides of eight and now the sliver is going to be sliver list and this list is going to have a delegate and the delegate is delivered child list delegate and what is it that we need over here the positional argument the children so the children is going to be a list and the first thing we need is a row so you're in the sliver childless delegate I want a simple text to show up which is user.name and then I need a style of constant textile where the font size should be 25 a little bit bigger than usual and font weight should be font weight dot bold so here it shows up my name now after this is done the next thing that I need is down below the same thing but with other eight so I'm going to have text like this with dollar and other rate so at the rate user.name the font size should be smaller 17 and it shouldn't be bold but the color should be palette dot gray color okay here it is now the next thing I need is the user's bio so we have text user dot bio I'll just remove all the string and here the gray color should be removed the font size should match this at the rate sign and here it is this looks good but bio is not showing up of course when we work on the edit profile feature you'll get to see it now later on we need a constant size box of height 10. because now I want to show in a row format the number of followers the user has the number of following the user has so to do that what am I going to do I'm going to create a separate widget here which is going to be follow underscore count dot dot I'm going to import material art I'm going to create a stateless widget and call it follow count and here we are going to return a row because we want to show the number of followers the user has and with the tag that this is followers and this is following okay so now we'll have final string count so like the counter and final string text then I'll require this through the Constructor and the children now I'll have a text that basically says the count so you have zero followers or five followers like that and we are having dollar count because this will be in an end format not a string format sorry okay now in the style we are going to have not stretch style style and we'll have constant textile because we want to have a color and the color should be palette dot white color the font size should be 18 and font weight should be font weight dot bull because I want to bold it right I mean this count should be bolded because there is more emphasis on this yeah this guy has 17 followers so like there should be an emphasis on this and we're going to copy this text paste it again with some width here so let's say a width of three you can also add you know a padding from the right side or from the left side depending on where you add the padding but I'm adding a size box and this will show the text so what is like it followers following what and this will have a gray color font size should be 18 the same size as this okay so you can create a separate variable for it here called and font size which is equal to 18 because both of them should maintain the same font size every single time so let's remove the constant and obviously this is a double so we can make this double font size okay now I can take this follow count and put it here but I want it again in a row over here we had a row because I wanted to show the counter alongside the tag that this is following but over here we want the followers entire row showing beside the following entire row so for that I'm going to create another row I have children and the first child is going to be follow count and here the count is going to be user dot followers dot link don't use current user here this is user.followers.link and this will be follow us now we are going to have something similar but above it which should be following and this should be users dot following dot link okay now let's see what we are getting we're getting one following one followers that shouldn't be the case but that's how apprite is functioning right now because you're directly getting the user's follower dot link so if you want to change this you can just have minus one because this happens for literally every user so you can just have minus one and there's zero follow zero following also to leave some gap between them we can have constant size works of width 15. let's have constant and yep this looks much better now I'll exit out of this row leave some space so I have height of let's say 2 and then I want to have a divider after I have the divider which doesn't show up so I'll just have a color color with palette dot white color come over here we have the divider showing up now below all of this divider I want a list of the tweets made by the user himself so if you are on this user we want to see all the tweets the user has made so I can come to the body and here we need to do that but even before doing that we have another step because we have to go to the user API and create an API or a function so that we can use it but we are not going to do that in user API we'll go to the Tweet API because at the end of the day this is tweet related we want to get the tweets made by the user so you can have future list of document get user tweets and then we are going to supply to it the user's ID we'll add the missing override implementation for it let's create async over here and now this is very similar to the get tweets functionality so we are just going to have that let's go up copy this paste it away up we want to list the documents in this database ID this tweets collection but the query is going to be different because here we want to check if the query is equal we want to get all the users tweets correct so you want to check if the uid is equal to the uid simple the Tweet collection has a uid property there we are checking if it is equal to the uid supplied by the parameter and then we are returning this now we can go to the user profile view your create a controller and this will be user profile controller dot dot and I don't want to write all the boilerplate code again and again so what I'm going to do is copy this controller from here paste it here and I'm going to make changes over here only so I'm going to remove the search user provider here I'm going to press option and select everything that has explore in it except this one so lab explore remove all of this then I'm going to have user profile controller also over here we are going to have small user profile controller and we don't need user API we need tweet API underscore tweet API then underscore tweet API should be equal to 8 API so let's have tweet API okay and this function is going to be get user tweets we are going to supply it the uid of the user well this uid is not to be confused with the uid of the current user if we do the current user's uid we'll get the tweets of the current user we don't want current user we want the tweets of the user on Whose profile we are and here we'll just do underscore tweet API this will be tweets Dot get user tweets we'll pass in the correct uid then we'll map through the tweets we'll do we'll return tweet Dot from map and also the return data type over your should be tweet so we have fixed everything of course we need to pass and tweet API provider over here and I think we are almost done over here let's remove the unused Imports now we just need to create a future provider and then only displaying part is left so we have get user tweets provider dot family and we want to get the uid of the user which is string uid then we want to have final user profile controller which is equal to ref dot watch user profilecontroller provider.nodifier and then finally we are going to return user profilecontroller.getuser tweets and then we are going to return with the uid of the user that we are going to get from the UI so we can go to the UI here we are going to have ref.watch get user tweets provider then we need the uid of the user which is user dot uid not the current user uid Make sure and then we need when now in case of data we have to do something error will give us s error and s t which we will return as error text where we have to convert it to a string and return and then a loading where I just have to show a normal loader and here we are getting tweet so I have tweets and what I want to do is return a list view Builder so that I can show that yeah this is all the you know things that I have and actually instead of writing all of this code why can I not just go to the Tweet list just copy everything from here not everything just this part and paste it away of course if you want your user profile to be you know real time working for example if someone likes a tweet or something you want them to see that in real time of course you should copy all of this but first what I want to do is just display the tweets as it is and we're getting this error of course because of the index so we'll go to the tweets indexes and what is this index well this is the uid equal part so I'll just do uid equal and we have said that these should be equal so this should be a key uid defending create I'll restart the app go to the user so we have test go where and all the tweets from test show up over here and you can see we have a little bit of weird scrolling effect as well so if you just go over here and come back you can see there is not the normal scrolling you can see it in this part sorry this part okay so if you want to see it again you can see it if we come back yep here it is now whenever we click over here it's not going to be real time of course there's no real time logic in r user profile can use a profile over here so even if we try to retweet it happens it retweets but it's not real time it doesn't show the one upgraded counter so for that you can of course add all of this logic by adding all of this so I'll just copy all of this and paste it to the user profile but I'm not going to do that you can do it on your own and if you face the same bug that we had faced earlier you should copy everything from the reply view screen so this part you can copy everything from here or let me just do it so I'll just copy this entire thing I'll come over here to the user profile where is it yeah and I'm going to return this thing now I'm going to import the Tweet model I'm going to have upright constants we are going to have get latest tweet provider and we don't need to add this logic over here so we only add this logic okay so now if we try to do retweet it shows up real time but just to make this look very simple what I'm trying here is just returning let's view Builder so if you want to check out my GitHub repository this will not be mentioned I've just showed it to you I can type a comment that make it real time or can make it real time by copying code from Twitter reply view okay so you can do that if you want but I'm not going to do that so now tweets are showing up over here now what will be the next step so the next step is obviously to edit the previews of profile so if the user clicks on edit profile we go to the edit profile screen and there we get the option to select a profile picture select a banner picture select uh you know the name changing bio changing all of that so let's get into that so for the edit profile screen we are just going to go in the view and add edit profile view over here and after adding that we are going to import material dot we are going to create a state full widget and this will be stateful consumer and we are just going to have edit the files View now I'm just going to import flood driver Port library I'm going to return a scaffold and here let's decide what we want well first of all in the body I want a column and in that column I want children and the first child that's going to be there is going to be exactly what we are put in the user profile so we are just going to go up and copy this thing the stack portion and I'm just going to copy it till here paste it in then close the stack and now we need the current user so we can get the current user which is final user is equal to ref dot watch current user details provider dot value and while we are getting that if it is null then we just want to show loader otherwise we'll get null check operator used on an L value and after getting this obviously let's just import theming and this looks good now let's see how this is coming about so when we click on the edit profile we should see the screen so here let's just put in the route so to get the route we can just go to one view file let's say home view copy it paste it here and then we have edit profile view route over here okay so now the next thing that's needed is whenever the edit profile button is clicked we want to go there so we'll go to the user profile and on this outlined button we'll check if current user dot uid is equal to user.uid so if both of them are equal we want to edit the profile so we are just going to use Navigator dot push and we're going to go to the edit profile view dot route save it now whenever I click over here I go to the edit profile view but I don't see anything and I'm getting this error over here so let's try to resolve this error first of all we want to give our stack a specific height so that it doesn't exceed the given portion so here the stack can hide I have a height of size box height let's say 200 it should not exceed that and here we have it our stack looks good over here next thing I want to do over here is not use position dot fill instead just wrap it with a container and in the container add width as double dot Infinity so the maximum amount of space height will be 150 so we'll save it the height has been reduced so the profile picture shows up here but since the Stack's height is this much you know 200 the profile picture seems to be on top of two screens like this then we need a decoration and the decoration will be box decoration we'll pass in Border radius which is border radius dot circular and we'll pass in 10 as a border radius cool so this is a bit rounded you won't be able to see it right now but yeah it is after this container let's position this we don't want it here we want it to go a little right and from bottom we wanted to go a little up so what we are going to do here is from bottom we want 20 and from the left because you want to go in right we want 20. so we'll save it and here it is this looks good now we'll reduce the radius so we'll keep at 40 and this looks better now the next thing is outside of this stack after the size box we need some text editing controllers because we want the name controller the bio controller so that we can change it so we have text editing controller final bio controller which is equal to text editing controller then we have dispose functions for it and then we are going to have name controller dot dispose biocontroller dot dispose so after this we can go down and here we are not going to have any styling for our text field actually because that's how Twitter looks it there is nothing no that doesn't feel to be any styling so we can just pass in the controller as name controller decoration can be constant input decoration the hint text let's put hint text as name save it and here you can see this looks better already but let's add a bit of padding so we have content padding of edge in sets dot all 80. and this looks much better now we can copy this text field and paste it over here now you can see we have two text Fields let's put some height between these two text Fields so we have constant size box height 20. save it and here it is looks better now we'll put this as bio biocontroller and save it also in the bio the bio can be longer so we want Max lines property to be let's say 4. and here it is the bio is much bigger this looks good so we're going to keep it this way now the last thing that we need is the app bar so we're here right at the top you're going to have an app bar where the title and the title is going to be text edit profile now we can const it and save it here you see we have our edit profiles showing up we don't want the center title so we can remove that so it shifts to the left hand side similar to Twitter and now we finally need an actions button basically a button over here so we are going to use actions and have text button over there now on pressed is going to be an empty function the child is going to be constant text of save basically save all the details here we save it and here we see the save button showing up this is cool now what I want to do is whenever the user clicks on this profile picture banner picture sorry or this profile picture we should be able to see open the image picker we have already created a function for picking multi images we are going to create a similar function but to pick just one image and also this typo is there so let's edit that and actually edit that and go to utils.dot create our function which is similar to this but this time we are just going to return one file which is Future file and this can be nullable we'll remove the list of images we have image picker we will remove all of this we get the image file over here because we are not going to pick Multi Image we are picking just one image and the source will be image source dot gallery so from the gallery we want to pick our image and now we can return a file saying image file Dot path obviously we need to put a check if image file dot is not equal to null so if it is not equal to null then we want to return a file but if it is not null then we want to return null I think I said it already I think I said it differently so this should be pick image so if image file is not null that means the user actually picked some image we're going to return the file with the path similar logic to what we had here otherwise you're just going to return null that the user has not selected any picture so now we can go to the user edit profile picture and now create two functions one for selecting the banner image let's work on that first so this is going to be asynchronous and then we are going to get the banner so we have Banner equal to await pick image not pick images and now we are going to check if Banner is not equal to null say Banner is not null what do we want to do well we are going to create Global variables here which are nullable and make sure that this is not apprite models.dot I've already told you that file also exists in apprite models what we want is import dot IO so we are going to import that and then we are going to have let's say Banner fight so this is null basically the point of this variable is that we want to display the banner file if it's selected on the screen so if we have it globally we can display it and we've done similar things for the edit profile not edit profile sorry we have done it for the create tweet screen as well the similar thing we are going to do here we have file question mark we're just going to have globally created and if Banner your the image selected is not null then we want to set States so that the build function rebuilds and then we have Banner file equal to Banner so basically This Global variable is equal to the banner that we have selected okay now what we want to do is just bind this function to whenever we click here so we want to wrap our entire size box which contains a stack not the stack let's just contain this one so we're going to wrap it with a gesture detector and we're going to have an on tap and in the on Tab we are just going to mention select Banner image here let's also add the property that if Banner file is not equal to null so Banner file is not equal to null then we want image dot file and we'll pass in the banner file otherwise we'll just check that the unit binary is empty if it's empty then we want palette dot blue color otherwise image.network now let's try to see if it works I'll click over here I'm going to select a image keep current selection okay this feels good I can select this image also but I want it to take the entire space possible so I'm going to have fit as box fit dot contain or cover fit with sorry so you're going to have box fit dot fit with we do it for your and also for year so we have box fit dot Fitbit so that it fits the entire width great now you want to do the same thing for the profile picture as well so we'll copy this have void select profile image then we want profile image if profile image is not equal to null then we want this so we'll have file graph file file and then profile file should be equal to profile image great now we can copy this go down in the circle Avatar wrap it with the gesture detector we are not going to wrap the position widget we're going to add the circle Avatar and we have on tap and pass in the select profile image now when we click over here we can select another image so we have leaf it doesn't show up so to show it we can do it right here but when you do it over here it doesn't fit for example if I just show it to you we have profile file not equal to null then I want to show file image right our images of file so you want to show file image profile file okay but this is giving us this error the argument type file cannot be assigned to the parameter type file so if I just do this it shows another the argument type object cannot be assigned to the parameter Type image provider object okay so we cannot do it this way we'll have to find another way another way is to wrap this so profile file is not equal to null then I'm going to have a circle Avatar widget that's right but here I'm going to have file image and I'm going to use the file as profile file so since we cannot do it in the background image we had to do it in the child property of gesture detector and now if we come over here you can see Leaf is showing up this is pretty cool now last thing is whenever we do all of these changes and click on Save we want to save all of this data in the users document so to do that we are going to close all the save files for now we're going to the user API and creating a function for it in the abstract class so we are going to create a function called future either void we are not going to return anything from this function we are just going to update the user data and that's it and while updating the user data we obviously need the user model because we don't know what has changed now I'm going to create one missing override and obviously I need all the try catch block so I'm just going to copy this paste all the boilerplate code have async over here and see what I want to change well over here I want to update the document that's first change database ID is correct collection ID is indeed users collection the document IDs usermodel.uid the data is usermodel.2map that means everything else is just fine so I can use this now I just want to go to the use of profile controller and create my function what is my function well void update user model or user profile and here I'm going to get certain things so I'll just put required since there are many arguments to be taken from this function I am putting it in a named Constructor Whenever there are more than you know two or three just put it in the name Constructor so that it's much easier first thing I require is the user model so I've user model then I want the build context so that I can display errors because a lot of stuff is going to go into this I want to upload images right then I need file and this file should not be apprite file it should be dot IO make sure it's not even dot HTML okay and now we can have Banner file and similarly we are going to have profile file why are these variables null because these variables can be null when the user doesn't select anything these are null so we don't want to change them correct cool now we just want to check if Banner file is not equal to null so if Banner file is not null what do I want to do well I want to upload the data or the upload the file to the storage get the download URL and add it to my user model simple enough we already have a function for it already created so I'll just import storage API where I've already implemented this so that it can be reused I'm going to require this through the Constructor and have underscore storage API equal to storage API now what I'm going to do is final Banner URL is equal to a weight so we'll put async over here underscore storageapi Dot upload image and what is the image that we are trying to upload well it's going to be in a list format and it's the banner file and now once we get the banner URL it's going to be in a list format because we are uploading a list but it's just going to have one thing one element in its list because we have uploaded only one file right and according to our logic and upload image we run through every file and add it to image links we are going to run only one time so it will have only one image and now I can just do user model equal to usermodel.copy web and I'm going to replace the banner URL so we have Banner pick as Banner URL add 0 because I want to grab the first element if you do first you know 0 add to 1 then it will give us an error because it is indexed out of range the list length is only one how can you access one when the numbering starts from zero similar logic is going to go in the profile file as well so if profile file is not equal to null then we are going to upload the profile file and then we are going to have profile picture as let's rename this to profile URL and we have profile URL at zero and then we are going to have final result is equal to await underscore user so we don't have access to user API we also want to get user API because we are going to call the user API so that we can store the data correct now we have user API and we can do required user API user API and underscore user API should be user API now I'll take this underscore user API put it here and call update user data function on it don't use the save user data if you use Save user data it will again create a document and it will override the existing document so that means your followers and everything might just go away so we have this done now we just fold it so that we know if it's a success or a failure in case of failure we show l dot failure you know l dot message failure and in case of success what do we want to do well we just want to pop because I want to get out of the screen so I can pop it right here now I'll go up at the top I'll add storage API which is ref.watch storage API provider I'll add user API which is ref.watch to user API provider and save it now all of the update user profile workers done let's go to our edit profile view add everything to this save button so we have ref dot read user profilecontroller dot Notifier Dot and what do we want to do well we want to update the user profile so we can update user profile pass in the user model which is user and this cannot be null because the user will only click on the save button after this user is equal to null all of these validations have happened then we have context Banner file profile picture already passed in and everything is now done also one important thing that I want to add is state so if state is true I want to add this and state is false I want to add here so basically is loading so it's loading has started is loaded as ending so here now I just want to share if it's loading then I want to watch the user profile controller provider if I hover over this this is object so I'll go up at the top in place of State Notifier provider add the type so it's user profile controller and Boolean after you add this you'll notice this is now the type Boolean and that is five for every state notify provider we created I mentioned the type but not for future provider or state or your stream provider now I can take this as loading and put it here so if it's loading or the user is null then we are going to show the loader otherwise our widget tree now I'm just going to restart my application I'm going to go to the user profile so I'll just have test I'll click on edit user profile let's select an image this one looks nice saitama also looks good I'm just going to rename myself as Revan and my bio will be hello there how are you and then click on Save we saw loading indicator for some time but no problem and if you see this has not updated but if I just restart my application go to the test user again you can see I'm seeing the banner picture but this is not quite correct so I can go to my profile view the user profile and here in the image.network I cannot fit as box fit dot fit with after I do this this looks much much better but other thing that did not change is the name of the user and the bio of the user why was that well that's because if we go back to the user profile here we have passed in the save sorry the edit profile if we go there you see we have just passed in the user we have not updated the user anyway basically this is the same user that was there we have not updated that bio so we don't know if we want to update the bio of the user or not so here what I want to do is user.copy with and I'm going to update the bio as biocontroller dot text and the name of the user will be name controller dot text but what if I just come over here and click on Save after changing these profile pictures it's just going to take the biocontroller.txt right now it's an empty string it will just take that I don't want that to happen so what I'm going to do here is provide with a default name in the NH state so what I mean by that is I'm going to have text editing controller let's call this late text editing controller also this will be late text editing controller bio controller remove that and in the init State method I'm going to specify this so name controller is equal to text editing controller and here we want to provide the text what is the initial text that needs to be filled in so the initial text is ref dot read since we're using outside of the build function in some NH state or dispose like methods the widget life cycle methods we are going to use ref.read and we are just going to copy all of this so let's paste it in I want ref.trade and we want the name of the user to be there but you can see this value is empty uh null right so if it's null then I just want to do if it is null then I want there to be an empty string otherwise nothing the same thing will go for the biocontroller as well we are going to have bio controller ref dot read but this will be bio and none now if we come from edit profile over here you can see test is there bio let's write it again hello there how are you and my name right now is going to be let's say whatever I'll click on Save nothing gets changed but if I again try to restart my thing so if I just restart my application like this I can just have test there's no user with the name test let's find Revan here there is and here is the bio hello there how are you this looks great the edit profile feature is now complete the next feature is the follow feature so that we can increase the count but even before that I want this to happen basically I want everything to happen in real time you saw when I edited the profile and came here it was not real time update I want that to happen so how can I do that with the help of real time so I'm going to do exactly that first and then go to the follow section because even while following when the user clicks on follow we want this numbers to update automatically so real time will help there as well so let's get started with real time first configure it for the profile screen and then we can go to the follow button so there are two approaches with real time you can take your first approach is not what I'm going to show you is the second approach basically we can go to the user API and here obviously the normal real time we are going to use so we are going to have final real time underscore real time and we are going to have required real time real time I'll show you the second approach but first let me just have underscore real time equal to real time when we get to the second part I'll let you know here let's just have real time as ref.watch real time provider and here we are going to have stream of real-time message just like we had for our tweet we're going to have that and we are going to have get latest user profile data we have profile data and that's it now we're going to create one missing override we are going to have here and now we are going to return underscore realtime dot subscribe now we need to provide a list of channels to subscribe to dot stream and what is the channel well we are just going to copy from the Tweet API so we have underscore real time dot subscribe let me just find here it is I'm just going to copy this and paste it over here so you have databases dot app right constant database ID but the collection here should be users collection dot documents and what I was talking about this is the first approach this is the first channel you can subscribe to the second channel that you can subscribe to is getting the uid of the user from here updated accordingly in the abstract class and just use that uid over here so we have collections of user collections dot documents dot dollar uid but this is not the approach you are going to take you can take this also there's no doubt about it now we can just go to the profile controller and we're going to have it created over here right at the top stream provider remember we did this for the Tweet controller as well we are not going to create anything in user profile controller we're going to go in the Stream provider directly so here we're going to have get latest user profile data provider so let me just copy this we don't need anything from stream provider let's just remove it and here we are going to have final user API is equal to ref.watch user API provider let me have user API provider and we are going to return user API Dot get latest user profile data okay now I can copy this go to my profile user profile view right here and now I can use my ref this is why we had used consumer widget right so in the body we are going to have ref dot watch get latest user profile data provider dot when and then we want to handle the error and the loading States first so we have error text and then we pass in error.2 string then we need loading loading is just going to be constant loader now I can copy this and in the data I can paste it right there so I have this so we're going to return the user profile now in the user profile we get the latest user profile data all of that now we're just going to check if latest or if data dot events dot contains just like we did for tweet we're just going to check if it contains the update property because you have updated the user profile right so if it contains this channel then we have to make some changes so what is it that we want to see well let's just copy everything from the user API first so we'll copy this thing and we're going to replace everything with upright constants with star so that you know it can be anything also remove this make sure this is correct and here you need to make sure that the documents after documents there is user ID so we'll just do dollar user model Dot uid dot update okay now even before that we have some other thing to do so databases dot star dot collections.star so this collections dot star is not going to be star because we don't want to see if tweets collection has an update no we just want to see if the user's collection has any update so we're just going to have upright constants dot users collection let's import upright constants then we have documents then we have uid and then we have update and now what I want to do is basically if there is any update I just want to take the user data convert it to user model and send it to user profile so we can send the same user model but only problem is we have used final over here if your view is final we cannot reassign it so what can we do instead well we can just make another user model we can call this copy of user which will be equal to the user model that we get from The Constructor now we can take this copy of user pass it over here pass it to this as well copy of user.uid and even here because this is not final and then we can say copy of user is user model Dot from map data dot payload okay so if any changes happen so if update is create called copy of user is user model Dot from map so we give it an instance of another user model and return the user profile with copy of user so if this changes this will return again having understood this let's restart also I think the loader is constantly going to load but before that what I want to happen is whenever I click over here I want to go to the user's profile right so to go to the user's profile I can go to the Tweet card and go to the circle Avatar this part right here I can wrap this with a gesture detector and have on tap Navigator dot push context and the route is where do we want to go user profile view dot route and then we want to pass in the user model the user model is user not the current user don't pass that in even by mistake it should be the user that we're getting from here okay good now if I click over here you can see constant loading this is the real time problem that I discussed in the Tweet section as well basically we are not getting any error we are not getting any data so it's thinking that we are in the loading state so it's continuously loading so you basically want to return user profile here and it should fix a problem now if I try to change the bio let's say how are you how are you two more times and save it you can see it is real time updated that's pretty cool now if I want to change the banner image to say waterfalls I'll click on Save and it shows up real time this is pretty cool right now the next feature is the follow button so whenever the user clicks on follow we want to be able to show the users followers to increase but I cannot do it from here because I'm on this account only so what I'm going to do is open up pixel the Android emulator and run it over there I'll see you when it starts working I'll also log in and do all of the authentication processes and then see you so for the follow I'm just going to close all the save files I'm going to go to the user profile controller and here I'm going to create a function called void follow user and here we're going to require some things the user model I'll explain all of this so why do we need all of this then we need build context and then we need the current user so what is the difference between the user and the current user well the user user is the person we are trying to follow the current user is us so we need both of them why because we want to check certain things so we want to check if the current user contains the user's ID so if so Suppose there are two users this is Revan user the iOS simulator user and this is Naman the Android emulator user now when the user Revan tries to follow Naman what should happen well first of all there should be a check so does everyone already follow Naman so if driven already follows Naman then there should be an unfollow button here not a follow button but if the user Revan does not have Naman in this following list then he can click on follow but when follow is clicked what should happen so if follow is clicked the following of Revan should increase and the followers of Naman should increase but if the user clicks on unfollow button that means that the user already follows Naman then the following of Revan should decrease and the followers of Naman should increase this is similar to the like concept basically if the user is already like the post should we add it and if the user has not liked it then we should add it like that only so here what we are trying to do is getting both the user and the current user and then we will check if the current user dot following so if we are the current user we want is my following containing the uid of the user we are trying to follow so if we are trying to follow that means you have already followed this means already following so if we are already following what do we want to do well there's an unfollow the button that's showing up so you want to remove the user from the followers list so we have user.followers so you want to remove ourselves from the user's followers list so we can just have user.followers dot remove current user Dot uid and one more thing should happen the current user's following should also remove the user's uid so it should decrease both the places the user followers and the current users following else we are not already following the user then what do we want to do well the exact process opposite process that's followed here we want to add the follower and we want to add the uid over here okay now what we want to do is user equal to user.copy with followers will be user.followers we have made that changes over here and then we want to do current user is equal to current user.copy with followers will be current users dot followers actually we need to do following because we are updating the current users following right and then we can have following if you didn't understand this process don't worry I'm going to give a dry run after this when we try to follow a user and everything works fine now we are going to a final result is equal to await underscore user API dot what do we want to do well we want to follow our user so we have to create those functions in the user API so let's go over there so let's go to the user API here we are going to add certain things the first thing is follow user and it's going to be future either void follow user and we just want to get the user model okay this user model is going to be the user model of the user because we're trying to update their follow count right that's what we are trying to do over here of course you're going to have that normal try catch all of those blocks also put an async over here put try catch block after copying it and here we are just going to have user.uid the data here will be a bit different the data will be followers and it will be user dot follows so we are just updating the document of user.uid which is the user we are trying to follow and we are just updating the user.followers because we have done that over here right now another function that we need is add to following function basically similar to follow user we are going to have add to following but this time we are going to pass the current user because we want to increase their following right so we can create one missing override we're going to copy this exact same thing paste it over here put async but this time when we update the document it should be following an user Dot following that's it this is pretty much it this is the two functions that we need after creating these two functions we can just call follow user we'll pass in the user Make sure to pass in user because we are incrementing the user we are changing the user's followers over here and now we do res dot fold in case of error show snack bar l dot message in case of success we'll have to do one more thing what is another thing that we want to do well the same thing the same function that we created obviously this is going to be async but add to following but this time it's not going to be User it's going to be current user because we have updated the following of the current user you can see that over here now we are just going to have rest 2 dot fold in case of error again show snack bar l dot message and in case of success as of now nothing we are not going to have state is equal to true and all of that is loading part because whenever we click on the follow user button all of that doesn't show up right now I can go to the user profile view actually the user profile and here we can just call the method in the else of on pressed basically if current user.uid is user ID then this is the edit profile right but if that's not the case else we are going to have ref dot read user profilecontroller provider.nodifier Dot follow user so we're getting just one epi exposed but inside of this one function there's a lot of stuff happening you can see that that's the main point of this architecture abstraction now after having and passing all of these three things inside of it so I'll just restart both the applications also I just got to know that here I've just added a follow thing so what I want to show here is is if current user Dot not current user sorry we can just have current user Dot following dot contains the user.uid so that means the same logic that we have applied to the user profile controller then we want follow unfollow button to show otherwise the follow button thank you now we'll just restart everything I'll just go to the naman's profile so let's go Naman and here if I click on follow button I get unfollow immediately I get one followers now if I go to my profile now there's two following and one follower over here because I've changed this back to users dot following dot length and user.followers.link because if we go to the noman's profile so if we just go over there Naman you'll see there's zero following and one follower because I just followed so this works fine on naman's following count but it doesn't work fine on driven's following count that's why I haven't I've changed it back to normal okay so the follow also works now are here there are zero followers because I unfollowed now you see I'll just go through the dry run so now we are checking if current user dot following so this is the current user it does my following contain naman's uid no it doesn't so we get the following button now if I click on follow what should happen according to my logic user.followers.addcurrentuser.uid that means this guy should get one follower and my following should increase so if I click over here one follower I'll go where I'll go to Revan one follower and two following my following increased now if I unfollow you can see according to the logic if it contains then we should remove the user follower so this should become 0 and my following should decrease by one so if I unfollow and go back to my user profile one following and one follower that means this works well so the following logic now works well now the next thing that we need to work on is the notifications feature basically this tab over here whenever the user likes a photo retweets a photo replies to a photo or follows you we want all of them to show up in the notification screen so let's get into the notification part we are very close to closing on our app a complete Twitter clone so let's get to the next section so for notifications I'm just going to close all the save files I'm going to the API and here I'm going to add notification underscore API dot dot and now I'm just going to create the abstract class just like we had before I notification API then I'm going to have future either void create notification and this create notification is going to be based on notification model so you will have to go down create a notification model so we have notification underscore model dot dot and then you have notification and let's think of the properties we need to ask first is the text so what is a text final string post ID final string ID the post ID is like suppose if the user likes to post a retweets a post you need the post ID so that when you click on it you can go to that certain post then you need the ID of that poll uh ID of the notification then the ID of the user who has who's who we need to send to so basically if I follow another person another person should get the notification and then we need the type of the notification so what was the type of the notification was it retweet user or the following user part or the liking user what was it so for that we'll have to create an enum so we'll go to the enums folder and here we're going to create notification type enum dot dot now this is going to be simple very straightforward we'll copy it paste it here and add our own Fields first one is notification type I'll replace this over here and over here then what are the notification enums that we are going to have well whenever the user likes so we have like whenever the user replies so we have reply whenever the user decides to follow so we have follow and whenever the user decides to retweet so we have retweet and now we want the same thing over here so we can copy this retweet have notification type dot retweet if the user decides to follow notification type dot follow if the user decides to reply then we have case reply and this will return notification type dot reply and if it's none of them then it's going to be like so we can just have notification type dot like okay now we can come to the notification model and have notification type notification type and generate a data class based on this now obviously we'll remove dot convert we'll have to make some changes in the two map from map but first let's remove these two now in the from map what we need well here basically we have added a extension on string so let's rename the extension also here this should be to tweet type so it should be two notification type enum then I can copy it and paste it here so we'll treat this as string dot notification type in this is very similar to what we did in the tweet model so make sure you understand this by going through that section again if you want to now we can have notification type DOT type let's remove this the idea should be removed because we don't want that ID and here it should be map slash dollar ID okay now having all of this done we need to create a notification based on this notification model now I can have my class notification API implementing I notification API now I can create one missing override also here we might require some things first is databases so we have underscore DB then we have notification API then we'll require it so we have data basis DB with underscore DB equal to DB and now to create a notification we are going to have async and we are going to go to the user API to copy everything you know the try and catch block everything let's just copy it and paste it in the notification API now what do we have to do here we have to create a document correct so we'll just go here and call create document now we'll import app right constants then we will have database ID now we need collection ID also but it can't be users collection it has to be notifications collection right because we stored all the users in users collection we stored all the tweets and tweets collection so all the notifications should go in the notifications collection so let's open our app right database let's create a new collection here call it notifications copy The Collection ID go to Upright constants add that here so we have one more which is notifications collection copy The Collection ID of notifications and paste it over here now we can have notifications collection as a collection ID now what should be the document ID over here so the document ID should be ID dot uni right because every notification should have its own ID and data here should be notification dot to map now we will return write null and if there's any exception we'll just throw it across sweet now this notification the create notification is going to be used in several other controllers for example in the Tweet controller when we like a tweet we'll have to create a notification saying that this user has liked your Tweet so this should happen so for now we will just make sure that whenever the user clicks on like button they get the notification over here and then we will work on the displaying part and making it real time and then we can work on the retweet replying and follow part okay so now I'll just close all the save files I'll just go to the Tweet controller where I have my like tweet here after the like tweet has been completed and it's a success in the right what do we have to do we have to create a notification so we'll have final notification API underscore notification API we are going to require this through the Constructor so we are notification API and then underscore notification API is equal to notification API what we are doing is basically just storing data on the app right database and getting it that's all so right here after we like a tweet what happens is whenever the user likes a tweet the counter and all of that increases but we also send a notification to app right that yeah the user has liked your Tweet right now so it should show up in this tab as well okay so here I'm just going to have notification API dot create notification and here I'll have to pass in my notification API related notification model but instead of doing all of this can we simplify it even further what we can do is just create a new feature here called notifications then we are going to have a controller and it's going to be called notification controller so this controller will basically modify everything it will create a notification model so that we don't have to create it again and again and it will handle the error processes that we have to face so here we are just going to create a state Notifier called notification controller we'll remove the Notifier from here then we have state node a fire Boolean false and then a state Notifier provider and then we are going to have notification controller provider then we are going to have notification controller Boolean and then we should have final notification controller is equal to ref dot watch okay not the sorry we'll have to return notification controller only my bad so here we are going to have final notification API underscore notification API we are going to require this through the Constructor notification API notification API underscore notification API is equal to notification API okay that's pretty cool now we'll pass a notification API as ref.watch notification API provider but we haven't created a provider for that API so let's just go right at the top and create a provider for it so we'll have notification API provider I'm running through this because we have already covered it many many times and we'll pass in notification API and for the DB it's ref.watch app right database provider easy enough now let's go to the controller and we have notification API provider now we are going to create a very simple function of void create notification where we are going to require the text we are going to require the post ID so what post was liked or what post was you know commented on then the notification type and then the uid so we have required string uid so what is the user Rider okay now we will just create a notification based on the notification model so we have notification we pass in the text post ID the ID is an empty string no uid notification type and that's it you're not passing anything in the ID because we don't have to save an ID app right will automatically generate it now we just need to call it so we have await underscore notification let's put async over here await notification API dot create notification pass in the notification model and we are done now we'll go to the Tweet controller and here instead of having notification API we will have notification controller notification controller so here it will be notification controller just change it in all the places and after the change has been made aware let's just go down take this create a notification so we pass in Dot create notification pass in the text which is tweet dot text the post ID should be tweet.id the notification type should be notification type dot like and uid should be tweet.uid basically we the uid is going to be the user to whom we are sending the notification so if it's tweet.id then it's going to be the ID of the Tweet if it's tweet.uid to the uid of the person to whom the Tweet is being sent and if we use user.uid then it will be sent to us only and that makes no sense okay so after this notification has been made I think we should only display it so before going there we just need to pass a notification controller to get notification controller we need to create a state notify provider which we've already created so just copy it come over here on a ref.watch notification controller provider dot note F5 now I think we can restart the app on both the devices also let's add some attributes here so we'll go to our notification model see what all fields are there text is there so we'll add text which is going to be a string and the size is going to be 255 required now the next attribute is going to be post ID which is also going to be a string required 255 then we need uid the uid of the user to whom this should be sent create the notification type string and create so now we have created the notification model now let's try to like some post after liking one post let's restart we're not seeing anything so let's try to print it out here why we are not seeing that so we'll go to like tweet and here we'll just try to print l dot message now if we try to like some post no error shows up but if we refresh nothing shows up over here as well so there's no error over here but we forgot to handle the error in this case so let's have a handle over here so basically whenever we have some this done so we have final result is equal to await this done and then we fold it and in case of failure we just want to do l dot message okay now let's try to like something here you can see the current user is not authorized obviously so we need to go to the settings we need to get to the role all the users can create or read the notifications but they cannot update and delete okay now let me try to like another post I'll refresh it and here we can see the document the text is showing up as hello but this is not the text we want the notification type uid and post ID seem correct so now let's give another message here the Tweet text should not be tweet.text it should actually be that the user.name like your Tweet so basically dollar user dot name like your Twee this should be the text now if I like some other post you see it should get added over here Revan liked your Tweet now if I try to cover here and like some post you can see the liking feature is not really working it's not working because of some logic error that we have made so let's take a gap from notifications part and see why we are getting this error as of now and after a bit of debugging I found out that this problem occurred because here we have passed in the user it should not be user but the current user now we made this error I should have rectified it earlier and that's my fault I'm sorry but why do we have to pass in the current user because if you go to the like tweet if tweet.lex.contains user ID so it should contain the current user's ID right so if it contains the user ID then we don't have to like it and all of that stuff so you need to pass in the current user not the user okay now if you try to like any post you can see we get to like it and it works properly so this was the problem now after fixing this problem now the next thing we need to do is go to the Tweet controller we are also getting the notifications correctly now we just want to display them so to display them in the notifications folder we are going to have views and it's just going to be notification views so we have notification underscore view dot dot now we can import material dot we can create a stateless and it can be stateless consumer so we have notification View then we can have consumer widget and here we are going to return a scaffold with an app bar saying this is the notification sent section so we have title constant text notifications save it and to see it we can go away we cannot see it so we'll copy this go to the UI constants paste it over here and we should be able to see notification stuff pretty cool now what we want to do is get all the notifications now this is similar to the Tweet functionality so in the tweet API will go we are going to go here and have get tweets so we're just going to copy this exact thing and paste it in the notification API so we can paste it over here but here the name is going to be a bit different so let's copy it paste it over here but it's not going to be called get tweets first of all let's also get document from apprite models it's not going to be called get notif get tweets it's going to be called get notifications and we'll be needing the uid of the user so what users notifications do we have to get and exactly this is going to be the function name and this is going to be string uid final documents list documents database ID tweets collection is not going to be there notifications collector but what is the filter that we need to apply we don't need to get all the documents that are available in the notifications collection right we only want to get the notifications which match the uid so it's going to be query dot equal uid uid so you want to get all the notifications from a particular user ID and then we return it and since I'm feeling confident about this what I'm going to do is also copy get latest tweet so that we can make it real time and work it without you know jumping through each and everything and here it's going to be called get latest notification if you don't feel comfortable with it I would recommend you to try it on your own you know first implement the future provider with this get notifications and then add stream provider but for me it's a lot of copy paste code so I can just have real time passed in directly so we have required real time real time and this should be underscore real time is equal to real time also this needs to be get latest notification so I can just go right at the top and have stream real time message and get latest notification and your The Collection should be notifications collection dot documents okay now at the top we are having real time which will be ref.watch real upright real-time provider and we're done now we just need to go to the notifications controller right here and we'll be having stream provider over here and in the Stream provider what are we going to have well get latest notification provider we want to get the latest notification so we'll remove the async star then we have final notification controller or notification API in this case which is equal to ref dot watch notification API provider and then we are going to return notification API dot get latest notification after having this we are going to have future provider and this is going to be get notifications provider then we are going to have future provider dot family and then we are going to have the uid of the user that we'll be asking from the parameter now here let's remove the print call we are going to create a model conversion thing so as you have done it before multiple times we're going to have future notification model or just notification get notifications we'll take in a string uid async I know I'm rushing through this but if you don't understand let me know in the comment section and I'll help you out with that we're just going to have await notification API dot get notifications we'll pass in the particular uid and then map through all the notifications get one particular notification and then just have notification Dot from map e dot data and convert it to a list let's also import the notification model so let's import it we don't have to import it from dot HTML or anything it's from the notification model and now you can see we are getting this error because it's defined this notification is defined in two places so what we can do is prefix this or just rename notification model I'm just going to prefix this as model and have model dot notification model dot notification model.notification Dot from map and this will be future list of model dot notification okay now finally I'm just going to create final notification controller which is equal to ref.watch notification controller provider and then going to return notification controller Dot and I don't have access to anything so I can just use dot Notifier to get access to my method of get notification easy enough now I'll go to my notification view in the body I'm going to have ref.watch and all of that stuff but before I get into that part what I want to do is just get the current user so that I can get the uid so we have final current user equal to ref.watch current user details provider dot value this cannot be null here we need to check if current user is equal to null then we want to show a loader otherwise no loader is required and we want to show the latest notifications now this is going to be very similar to what we have done earlier what earlier well just the user profile view so we can go over there not user profile view sorry to wait to eat View the Twitter reply View I can just copy all of this code from here including all the error loading all of those stuff and paste it over here now we have to resolve all of these errors so let's resolve first let's import the common dot dot so that we have error text and loader now in the loading we don't have to show anything like a tweet card in fact we need to show notification tile so for now let's just put a text of let's say tweet and this is not even a tweet this is notification and you're going to get notifications index so to resolve this let's go directly at the top and here it's not going to be get replaced on tweet it's going to be get notifications provider and then we'll pass in the user's ID so we have user the current user Dot uid then we keep track of get latest notification provider we get some data then we just check over here so we don't have to put the if condition so we'll go down remove the fifth condition and here we are going to check for upright constants so we'll add that but not tweets collection the notifications collection and we are looking for a create Command right we are not looking for any update command because it's never going to update so let's remove all of those update logic and it's not going to be notification or tweets it's going to be notifications so I can insert that this can be notification Dot from map obviously we'll again have to import notification as model just like we did in our notification controller so if we go there just like this we'll have to copy it and paste it so we can go in the notification view paste it and now we'll have model dot notification Dot from map okay now this should be notifications dot length notifications at index and this is one notification and now we'll just return a text which just says notification dot to string even here it's going to be notifications dot length we'll get one particular notification and two string simple and good I'll remove the loading page from here I'll come back over here and you see apprite exception index not found we basically want to create a new index here saying uid equal so it's going to be a key and uid should be in descending order created rerun the application go to the notification section and we get this error so we are getting this error here basically because we are not removed expanded there's no need of expanded because we are going to get the entire body there's no column or anything even in the loading part we'll just remove it and we'll restart the app go via and you can see the notifications showing up but do we want to show all the notifications that are present over here not really we only want to show the notification which matches the current user's uid so here what we want to do is get the latest notification right so you have latest notification in a model format so we'll cut and paste it over here and here I'll check if latest notification dot uid is equally equal to current user.uid then what do I want to do only then do I want to insert it right at the top so we have latest notification if it does not match then I don't want to add it why would I add other person's notification to my notifications tab you can see over here we are listening to all the documents being created right this was the second approach I was talking about you remember when we were doing tweets part a user profile part there were two here we could add the document ID or we could just do this if condition over here anyways now that it's done we can restart the app underwear let's see this a guy has some things and for our pixel let's rebuild and over here if we see there are some notifications here as well now we just need to display them in a good format so to display them we are going to create a new widget here call notification tile import material dot create a stateless widget called notification tile and then we are going to have final notification notification and require it through the Constructor but not the notification from material.dot no not that one we want it from this one right you can just name your notification and notification model so that you have to avoid this prefix every single time so now we'll have required this dot notification now here we are going to return a list tile and if you've seen Twitter you'll know that in the leading icon it really depends on the notification type so if notification type is follow it will give you some other icon if it's like it will give you a like icon like that so here in the leading part we are going to check that so if notification dot notification type is equal to notification type which is the enum is equal to follow if it's followed then I want constant I can as icons dot person and I want color to be palette dot blue color otherwise we are going to have another logic basically if notification dot notification type is equal to notification type dot like so if the user has liked it what do you want to show well in that case I want to show SVG picture.asset via 3G picture.asset because I have an SVG file for it why not use it so it will be like filled icon the color will be palette dot red color and height will be 20. you know just so that it remains at the same size as that of a follow button or the person icon that's being showed when the user tries to follow someone otherwise the notification dot notification type is equal to notification type dot retweet and if it's retweet then what do you want to show well it's going to be an SVG picture.asset again so we'll have that but it's not going to be like field icon it's going to be the normal retweet icon with white color in it and if it's none of these we just don't want to return anything so this is the big logic that we had let's go through it again if notification type is follow so if the user has followed we want a person icon like this to show up if it's like then we want a like filled icon and if the user has decided to retweet then we want a retweet icon and if it's none of them we don't want any icon to show up next is the title and the title is going to be the text which is notification dot text simple enough now I can take this notification tile and use it in the notification View and return it so we return notification tile and return notification now we'll copy this notification tile and paste it over here now we'll restart both of them and see what we get so here if I just see everything is related to like what I'm going to do now is you know just restart everything because I want to delete everything I'll delete everything and then I'll get back to you because I want to test it out fresh so I'm finally done deleting everything I'll just restart my applications and here when I try to like a post that's given by let's say Revan let's find a post given by ravan let's say hi hey guys one and click over here and you see no one liked your tweet this is good now if I try to like a post given by Naman so I'll just give hey and then click on tweet you can see hey showing up I'll just go at the top here it is I'll stay here to show you that it's real time I'll click on heart icon and you can see rewind liked your Twee this is awesome that means the entire notification process is now working now let's just get it done working for literally all the features retweet comment icon when the user replies to someone so all we need to do is basically close all the save files go to tweet controller copy this and paste it everywhere so when you re-share a tweet and it's a success before you say retweeted what you need to push is this thing notification dot create notification it's going to be current user dot name liked your Tweet so that means we have liked your Tweet and the uid should be tweet.uid tweet.id tweet.retweeted by is the user who retweeted tweet.uid is the user whom will send the notification to okay now let's try it for something so if I try to retweet noman's retweeted you know I'll just come over here and see and this should not be light your Tweet sorry this should be reshared your Tweet that's why we couldn't see the like part it should be retweeted now if I retweet naman's retweet you can see re-shared your tweet this shows up pretty cool now the next part is whenever the user decides to comment on other user so I can copy the same thing I'll go down where there's reply so I'll just go reply and there's no reply over here it's in the Twitter reply View and here down below we have the on submitted property we have passed in the reply to so here we also need to pass in another thing replied to user ID so basically we don't in the share tweet we don't have access to a field called reply to user ID so whom are we trying to reply to what is the user ID of the user to whom we are replying to right so we need that so we have replied to user ID and this should be tweet.uid okay so if we come back over here replied to user ID is exactly what we need to send out notification because it's at the end of the day tweet.uid and everywhere we have used tweet.uid to send to the notification to a person because we have replied to their tweet right we're going to get it through tweet.uid and we have accepted that over here so now what we need to do is just take reply to user ID share it literally everywhere share text tweet and share image tweet both of them accept them in both of these functions so we'll just have required replied to user ID string and required string reply to user ID and here after the success we are just going to check also put a bracket here if replied to user ID dot is not empty so if it is not empty that means I replied to user's ID is not empty that means there is some ID and if there's some ID we want to send a notification so let's just copy this go down below and paste it over here and here we just want to say reply to your Tweet so the user.name the current user replied to your Tweet and this is reply the post ID will not be tweet.id don't make this mistake basically tweet.id is this tweet's ID right and here the ID is empty string so if you try to put post ID it will give you an empty string over here and your notification won't get sent what you need instead is this this RS ID because this R is basically the tweet that you get after uploading it to Upright when you upload it to app right you get a particular ID because we have used ID dot unique while sharing the Tweet so here we get R and we're going to use this R to get the ID and we get that using r dot dollar ID so the post ID should be r dot dollar ID and the uid should not be tweet.uid because tweet.uid is user.uid we do not want that the uid should be replied to user ID okay the same thing is going to be there in the share image tweet as well right here we're just going to have r and we're just going to have this simple and easy the state is equal to false will also come over here after all of this even for the share text tweet let's go over there the state is equal to false will be done only after the notification is sent now in the create wheat view let's see what's the error we need to provide the reply to user ID is going to be empty over here and it's it's empty we are not replying to anyone if you're not replying to anyone the notification does not get sent to anyone might that make sense now let's rerun it let's reply to someone so let's say I want to reply to Naman so I just say hey what's up and then click on done now if you come to the notification section you see ravan replied to your Tweet and for the reply we did not have any icon so I did not have any icon over here even according to our logic so if you have an icon do share it in the comment section or you can just have it in the leading icon widget okay now the last part is The Following part so whenever we try to follow a user it should show up in the notification section there as well so I'm just going to copy this go to the user profile controller and if it's a success at the end this always gets sent in the end basically after all the logic process has done we want notification to be sent and here we are going to require notification controller so we have notification controller underscore notification controller required notification controller notification controller underscore notification controller is equal to notification controller that has a lot of stuff but at the top we can resolve the error by passing a notification controller as ref.watch notification controller provider dot Notifier and over here what are things that we need well we are going to create a notification saying user.name followed you but is it going to be user.name no it's going to be current user.name right because it's us who has followed the other person what is the post ID going to be well we can find that but there's no finding it out because a follow cannot have a post ID because we are not doing anything related to tweet right so it's going to be empty what is the notification type going to be well it's just going to be follow and the uid is going to be user.uid not the current user.uid the user.uid so we have added this now let's try to follow one user so let's say I try to follow from here Revan so I can just see I'll click on follow it doesn't really get sent you can see Naman followed you shows up so that means the entire notification section now works you can retweet you can do anything and it will work now the left next section is basically listing out everything that one hashtag has basically if I have one tweet that has hashtag rivon this is nice and then I tweet it and then I have another tweet that has hashtag rivon not at the rate #nice hashtag wow and you then click on tweet and even this person has hashtag rivan in some of their comments so they have a hashtag hashtag haha hashtag off and then click on tweet you see there are three Hashtags with driven and when one of this hashtag is clicked you know this hashtag should open up in a different screen the hashtag screen and it should show you all the posts from that particular hashtag okay so this is what we are trying to achieve so this is what we'll do we want to get all the posts from one particular hashtag and if you see our database structure it's well suited for that we had made this for this purpose only if you go to the tweets not notifications and see aware the hashtags have rivan haha and open it right so we just want to check if the array contains hashtag ravan or not if it contains hashtag rivon or whatever you click on hashtag nice hashtag wow any of this is clicked you just want to check in the ira that it's there if it's there then we just display everything so this is what we are trying to achieve and this should be very simple this is can actually be a challenge for you you can try to do it on your own if you are able to do so then you've properly understood app right till now so try it on your own it should give you confidence but if you can't then we can do it together right now so let's start we'll go to the vs code so what we are going to do is close all the save files and we are directly going to go in the Tweet API and create a decent tweet so what is the last function of this tweet API it's going to be future list of document this exact same thing because we are going to get all the user tweets not the user tweets but get the tweets by hashtag and here we are going to get a hashtag right so the implementation is very similar to get user Tweets we're just going to copy this paste it away it's going to be asynchronous we are going to list all the documents in the tweets collection where the hashtags should be equal to not really because hashtags is a list we cannot equate it here we want to search so in the hashtags array we want to search that the hashtag is present and if the hashtag is found then we want to return all of those documents right so we will use query.search hashtags and then find a particular hashtag and then we'll return the document now all we need to do is go to the Tweet controller create a function very similar to get user tweets or get replies to tweets something like that we're going to get the documents but here the name will be get tweets by hashtag we'll mention the hashtag from the UI so the future provider is also going to be family and here we're going to have tweet API dot get tweets by hashtag we'll pass in the particular hashtag and all of those conversions will take place now we just need to go to the Future provider we'll have to create one and this will be very similar to rest of the things that we have get tweets by hashtag provider future provider and this time we are going to get a string of hashtag and then we are just going to pass that to the get tweet by hashtag function simple enough now we can just go to the view create one view which is hashtag view dot dot and here we need to import material dot we want to create a stateless consumer widget called hashtag View we're going to import flutter riverpod Library we are going to return a scaffold here we are also going to accept a string hashtag so basically this hashtag is whatever the user clicked on so if the user clicks on this hashtag we will navigate to a new screen where hashtag will be written in the title and all the posts from this particular hashtag will be seen so let's require it through the Constructor so we have required this Dot hashtag let's put this inside of the name Constructor now in the app bar we are going to have Abba and the title is going to be text hashtag okay and now we are also going to go to the home view copy this route put it in hashtag View and return hashtag view from here just like we've done multiple times before but this time we're going to take it from the parameter so we have a hashtag and we pass that in to the particular hashtag now what do we want to do well whenever the user clicks on this hashtag which is identified so how do we identify and where do we identify the hashtag we do that in the widget your hashtag text so what we can do is whenever we identify a hashtag over here we can just have something known as recognize the year and we can pass in tab gesture recognizer this is a Syntax for it we create an object of tab to adjust a recognizer and we give it a property of ontap and the ontap property is equal to an anonymous function and here we can write whatever we want so we basically want to have Navigator dot push and we want to push to the hashtag view so we have hashtag View Dot route and we pass in the particular hashtag what is a particular hashtag element this is what we had right element dot starts with hashtag we just push it to hashtag view.rout after we have completed this we can go to the #view restart our application on iPhone and Android click on driven let's say and we get hashtag ravan now the thing that's left is just to display everything now to display everything VR scholars in it now we can just go to the body and you know again instead of typing so much we can just go to the Tweet list copy everything from there and see what all stuff we need so I'm just going to copy it paste it here import the loader Sav common import tweet card survive tweet card and I don't think we need any of this I'm not making it real time of course if you want to make it real time go ahead but I'm not making it so again I'll have to remove all of this all of this part I also have to remove this returning part all I need is get hashtag tweets by hashtag provider and pass in the particular hashtag and when there's data we'll get tweets and we can display that and now we can remove this bracket this is an extra bracket it seems even this one and now we don't have any error we're basically returning a list view Builder with all the tweets if you want to make it real time you can go ahead and make it there's no problem with it I just removed it so that that's complete no complexity you already know how to make it real time we just remove the real-time code and now you can see we are getting this error index not found hashtags when we get this error we go to app right then we go to our tweets indexes create index and your let's just say search by hash tag and this is going to be let's say full text because it's search and then we are going to have the attribute so what is the attribute we are searching by hashtags order descending create refresh the app and then click on driven you see all the tweets which has driven in it that means this is working our app is now working even to show the latest hashtags this was very simple right you just need to understand the logic for one thing and you'll get everything else now the next thing is to close all the save files we have completed all the features except one which is Twitter blue so let's get into it to get into Twitter blue what we need to do is go to the home View and your basically whenever we click over here we want a drawer to appear and in that drawer we should get my profile so that when I click on it I can go to my profile and the option to convert to Twitter blue and the logout option so these three things are the things we need to work on and you're done with the application so you're in the home folder we are going to get widgets and the widget is going to be side draw dot dot so let's import material art let's create a stateless widget call this side drawer and actually this will be a consumer widget so let's import that add in a widget ref and now let's have a safe area so that you know our drawer doesn't merge with the top knob notches over here and then we have drawer then we have a child a column and in that column we have children and what are the children that we need well first of all is a lift Style and in the list style we have a leading icon which is const icon icons dot person then a title which has constant text my profile and an on tap to it now what I'm going to do is just attach this drawer to the home view so here I'm just going to add a draw a property and pass side drawer to it let's have constant over here save it and whenever I click over here my profile shows up but this is not good because this is not black in color I just wanted pure black so I'll just pass in the background color property AS Palette dot background color if I save this much and go back you can see this is black but I want the font size to be increased now so I can just go ahead and have style as textile with font size as let's say 22 much bigger and looks much better you can also increase the size of this icon so let's say size of the icon is now 25 this looks good but maybe 30 might look better and yep it does now you can copy these list tiles two more times another one is for Twitter blue and for Twitter blue the icon is going to be payment because well you're going to take money from them Twitter blue and if you don't want this to happen what you can do is just use SVG picture.asset and then you can use the Twitter blue verified icon that I've added in the svgs but since I just want to troll I'm just going to use the payment one and the last one is the logout option so you can just scroll down and have log out over here and this is going to be icons dot logout save it and here we have it now I just want to leave some space from the top so I can just have let's say a constant sized box of height 50 if I do this much and come this looks better all right now the next thing is whenever I click over here I want to navigate to my profile page so to do that what I'm going to do is Navigator dot push and I want to go to the profile page so I'll just say user profile View and then I have to pass in the user model to get the user model now I'll just do final current user is equal to ref.watch current user details provider dot value and then I'll check if current user is equal equal to null then I want to return a constant loader otherwise everything else is going to work now I can just pass in the current user not over here dot route and I'll pass in the current user over here great now if I just click over here I should be able to go to my profile and this works pretty good next thing is when I click on Twitter blue I should get a verified badge next to my name so to do this you'll have to go to the user API scroll up create and actually if you see over here in the user API we have something known as user update user data so I don't think we have to create a separate function for its Twitter blue to update the sjw of course so what I'm going to do is close all of them go to my site draw and here I'm directly going to say ref dot read user profile controller provider.nodifier dot update user profile then I have to pass in the user model the user model is going to be current user Dot copy with and now I want to copy with what if Twitter blue should now be true this is the updated user data that should be there the banner file is not there null and the profile file is not there so it should be null so obviously if we go to the update user profile this is updated user model since both of them are null these two functions won't run or the if blocks won't run and then we call update user data it passes in the user model which is Twitter blue is now true okay and now the last thing that I need to do is just go to my tweet card and here I just want to display my verified icon so what we are going to do is scroll up right here you can see we have container in the container where we have margin here we are going to check if tweet dot is not tweet sorry if the user dot is blue so if the user is Twitter blue then we want a margin of 1 otherwise a margin of 5 from the right hand side now we'll remove the constant as well why is this logic there because if the user is Twitter blue then we will have a Twitter batch beside it right so we want a very less margin to be present but if there's if the user is not Twitter blue it's fine if the margin is little bit more to the right and now we are just going to have after the container if condition so if user is Twitter blue then we want to have an SVG picture dot asset of asset constants Dot verified icon now we'll save it nothing shows up because no user is to a w as of now so now let's try to convert one user so I'll click on Twitter blue here nothing happens but if I refresh my application on both the devices I see the Twitter blue icon great but this Twitter icon if you zoom it in it's very close to this username so I want there to be a margin from the right hand side so for that I can either wrap it with container or a padding and here have dot only and from the right hand side I want five so from the right hand side I have a padding of 5 and this looks much better and less congested you know so if the user is Twitter blue it shows up now we also want to show it on the user's profile right beside their name over here so now we can just have this user.stradw we'll go to use a profile view in the user profile just below where they mention their name right here we're going to wrap it with a row widget and have something like if user is Twitter blue then we want this thing where is it this padding to be present with the icon so I can import flutter SVG I can import asset constants and save it after I do that you can see I get my Twitter blue icon over here but I don't I don't want the padding to be from the right hand side I want it to be left hand side so I have it and this looks so good maybe we can do two whatever way you prefer three whatever so I'll just keep it three and we get the verified symbol over here and if the user is not Twitter blue we can see that over here that they are not Veda blue and of course Twitter blue is eight dollars so if you want to implement payment integration I'll create a separate tutorial for it you can check it out I'll mention it in the cards above when I created but if you already have an idea or if you want to use Google or Appleway which I've used in my other tutorials what you can do is you can implement it here before the side drawer when you click on tap over here you can create a method and create a separate controller so that you can add your own you know Twitter blue thing your payment integration so you can add it in the on tap over here and then only update the user profile so if the payment is Success you can update the user profile else you will not so now the last feature we are left with is the log out feature so for that we are going to go to the auth API we're just going to have future either void log out I'm just going to have create one missing override we are going to have async we're going to have our simple try and catch blocks and here we don't want anything we'll just have if await account dot delete session or if you want to delete multiple sessions so you want to delete sessions from all the phones so you can do delete sessions and just do this so it will log you out from all the devices but I only want to delete session from this part and I have to mention the session ID so what is the session ID well the session ID is basically the login session that it gives us that ID but since I don't have it what I can do is current when I use current aware it will delete this current session ID app right identifies it and does it for me now I'll just do return right null meaning that is a success and in case of failures yes all of this is done now we can go to the auth controller we can create avoid function for logout so we avoid logout and then we can have underscore auth API dot logout log out and we can await this final result is equal to this also async now result.fold if you want to handle it some way you can do it but in my case if it's a success what I want to do is just do Navigator dot push and remove until then pass in the build context the new route will be the sign up screen sign up view dot route false so basically this will pop off push and remove the screen until we get to the signup view dot route and then we'll pass in the build context now to use this what we want to do is just go to my side drawer just use your ref dot read auth controller provider.nodifier Dot logout pass in the required build context and done so we will restart the entire app and now if I try to log the user out let's log out we've logged out now if I try to restart and see if I'm on the login screen now yes I am on the login screen now because account is now null we have deleted the session so we have developed an entire application an entire Twitter clone where you are able to like retweet comment on a profile put hashtags identify links click on links to go on a new link you know in a browser search for users follow a particular user and follow a particular user see the notifications here even if it's replied e-share like anything and also able to add Carousel images to your application and obviously the most important feature that is Twitter blue so I hope you learned enough from this application if you did make sure to leave a subscribe to this channel this was it for this tutorial thank you so much for watching and I'll see you in the next video
Info
Channel: Rivaan Ranawat
Views: 37,106
Rating: undefined out of 5
Keywords: flutter, flutter tutorial, flutter 3.7, appwrite, appwrite tutorial, appwrite flutter, flutter appwrite, flutter appwrite tutorial, riverpod tutorial, appwrite flutter riverpod, flutter project, twitter clone, flutter twitter clone, flutter riverpod, flutter riverpod tutorial, full stack project, 10 hour flutter course, flutter full course, appwrite full course, flutter clone, firebase competitor, riverpod full course, flutter tutorial for beginners, flutter ui tutorial, dart
Id: XnxZLhtkFeg
Channel Id: undefined
Length: 543min 4sec (32584 seconds)
Published: Thu Jan 26 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.