Flutter Clean Architecture Full Course For Beginners - Bloc, Supabase, Hive, GetIt

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we'll be diving into the world of clean architecture with flutter we'll be building a fully functional blog app that includes features like signup login keeping users logged in uploading blogs displaying blogs reading blogs with a dynamically calculated reading time and caching for offline access we'll be using flutter to create the UI super base for the backend block and cubid for State Management get it for dependency injection hi for local storage and FP dot for functional progr programming the principles we'll cover in this course are applicable beyond the specific Technologies used so you can follow along with any other database State Management or service locator you're comfortable with the prerequisite for this video is Dart and flutter Basics if you're new to it you can watch the 20 hour tutorial present on the channel as mentioned earlier we'll be using blog for State Management if you're not familiar with it you can either watch the 2hour tutorial to learn it or use a state management tool of your choice before we begin I'd like to thank nymous mlock for reviewing the code also subscribe cuz the button lights up when I sa it now let's get into the video all right so the first step is to create and set up a flutter project to do that first of all go to your terminal and in there migrate to the folder you want to create your flutter project in after you've done that run the command flutter create followed by the name of your project I'm going to call this blog uncore app and then hit enter after the project is created I'll go to the project directory and then open it in Visual Studio code if you want you can open it in Android Studio or any other IDE you want but I'm going to do this in vs code after the project opens up in vs code what you have to do is go to the lip folder in main do. file and from here you're going to go down to this Bottom bar select the devices and you can open any simulator you want I'm I'm going to run this in iOS simulator so I'll start this and once the iOS simulator is up and running I'm going to go to the Run tab and click on run without debugging I prefer to run my applications when I first create a flutter project just to ensure that everything's set up properly all right so our app is now up and running as you can see it works properly the way it is intended to so our flutter creation part is done correctly now the next part is to understand the overall flow of the app the folder structure understand clean architecture and then we can get into the code to understand the entire flow of our app I've created this flowchart this will be our guiding path throughout the tutorial helping us focus on the features of the app let's go over it once in the beginning our app is going to start when the app starts we want to check if the user is authenticated or not if the user is authenticated then we're going to check if the user's internet interet connection is present or not if the internet connection is present we're going to fetch our blogs from superbase superbase is the database I'll be using but if you want you can go ahead and use any other database or any other backend of your own choice now what if the internet connection is not present in that case I want to display the blogs from local storage and obviously the blocks from super base or the blocks from local storage will be displayed on the homepage now what if the user is not authenticated in that case I want to display the login page the login page is going to have Fields like email password and a button to submit the form but other than that it will also have a text that reads does user have an account if the user has an account they can click on the button login and go to the homepage but if they don't have an account they'll be going to the sign up page this is the entire flow of our application it's pretty simple it's pretty simple the app only has two features the first one is authentication and the second one is blocks in authentication we'll be including sign up login State persistence Etc the in the blocks part we'll be managing the creation and the reading of our blocks so now that we've understood the entire flow of the app let's go ahead and dive into the folder structure used in clean architecture to understand the folder structure used in clean architecture we must first understand the components that make up clean architecture the three main components of clean architecture are data domain and presentation layers let's use an analogy to understand them imagine you're building a house in this house each floor has a different purpose just like in our diagram here each layer of the architecture serves a different function in a software building at the very top we have the presentation layer this is like the living room where everything looks nice for guests it is what users see and interact with this includes all the widgets which are like the furniture the things users can touch and use and behind the scenes we have a state management tool which is like the butler listening for your requests and then notifying the rest of the house to respond next floor down we have the domain layer think of this as the internal planning of the house the blueprint if you will it outlines what needs to be done but doesn't get involved with the specifics of how it's done this is where use cases come in they are like the instructions or actions that need to be taken when something happens upstairs in the presentation layer the entities are the standard rules or the consistent elements that don't change much kind of like the beams or the loadbearing walls in our house they are the Core Concepts or objects we are dealing with no matter what happens moving further down we enter the data layer here's where we get into the nitty-gritty behind the scenes systems that make everything work it's like the basement where all the machinery and storage is in this layer we've got the repositories which are like the store rooms that manage all the stuff you need they talk to the entities to understand what they need to return store or retrieve within this data layer we have two special sto rooms one is the remote data source and the other is local data source remote data source is like a grocery delivery service it goes out to the external world to get fresh data the other the local data source is like your pantry it keeps data Sav locally so you can access it quickly even when you're offline all the arrows that you can see over here are the paths or hallways in your house showing how people or in our case data and requests move from one place to another making sure the information gets to the right place at the right time the whole system is designed so that each part does its job staying out of each other's way but working together to keep the house running smooth smoothly so I hope you have a brief understanding of clean architecture now let's understand the layers in more detail so first the presentation layer as I said these are widgets and pages that will be displayed to the user the users can interact with this page as it contains the user interface now how do we know what data to display over here and what state our application is in are we in the loading State meaning are we fetching the blocks from an external database or do we have a list of blogs ready or if there's an error all of that logic is contained in this presentation logic holder and we're not using change Notifier we're using block but if you want you can go ahead and use any other state management tool of your choice so we know presentation logic holder is going to decide if you want to display the loading State the error message or the success part but for that we'll have to get a real data right and that's why we contact the domain layer the domain layer contains use cases and entities as we saw but it also contains one other thing that I didn't talk about and that is repository again so we have a repository in the data layer and a repository in the domain layer we'll understand that in a bit but what does use case do over here use case contains a single class or a single function that can be called in the presentation logic holder it exposes just one functionality of the app for example if if you want to sign the user up we'll call the sign user up class or function from use case that's all it does it doesn't perform more than one functionality but yeah you can have multiple use cases for example you can have a use case of signing up the user you can have a use case of logging in the user you can have a use case of getting the current user data so you can have multiple use cases but one use case is only going to perform one task then we have The Entity over here the entity contains the structure of the main state of our application so for example if you're fetching a list of blogs the blog is going to be the main data in our application so entity is going to contain the structure of a Blog so it's going to be a simple class that will contain all the properties of a Blog then we'll have the repository layer over here and note that this is the repository in the domain layer what this repository is going to do is contain all the functionalities that should be present in the data layer therefore this repository is going to be an interface it's going to be an interface that will decide how our repository in the data layer is going to look like if you remember in the domain layer I said that this is the layer which outlines what needs to be done but doesn't get involved with the specifics of how it's done so with the repository layer we specifying what needs to be done but we're not actually doing it it it's just an interface interface just contains function declarations they don't have the actual function implementations now after the repository in domain layer is created we have the data layer repository and this data layer repository is going to contain the actual implementation of whatever methods are defined in this repository interface as I said data layer gets into the ntegrity behind the scen systems that make everything work then we have our models which I'm going to skip for now and directly go to the remote data source and the local data source remote data source is going to fetch data from an external database in our case it's going to be super base local data source is going to fetch data from our local source and we'll be using hi to do that if you want you can use any other local DB you have in mind for example sqf light isar but make sure to not use flutter secured storage or shared preferences because they use to store simple stuff they're not used to store entire blogs which we are going to do so these remote data sources and local data sources are only going to have calls made to the external database now whatever data we get is going to be raw data right we either going to get a map Json or a string we need to convert that raw data to a model and this model is going to be structure of the state that we fetching so if you're fetching blogs it's going to contain the blog structure over here with properties defined inside of a class and it's also going to have two extra functionalities for example from Json and to Json so it will convert that raw data to a model using that from Json function and if you want to upload some data to a database then you can again use this model and convert it to a map so that the data can be stored in the database now you might think that hey models is just the entity right and that's true model is an entity because entity also contains the state of the main data in your application and model also does that the only reason we're not using entity in data layer is because it's present in the domain layer and domain layer needs to be independent of the data layer as I said before the whole system is designed so that each part does its job staying out of each other's way but they work together to ensure that the application runs smoothly then we come to the repository implementation that's present in the data layer and now I think you might understand why we have a repository interface in the domain layer and repository implementation in the data layer domain layer has to stay independent of data layer so we cannot directly have a repository that's talking to a remote data source we need a repository which is present in the data layer which talks to the remote data source and the interface repository that's called in the use case so I hope hope you understood this entire diagram the trickiest thing to understand in clean architecture is why domain layer and data layer have repository like this why they have an interface in the domain layer and the actual implementation in the data layer I'll again repeat this in the data layer we have the actual repository implementation and in the domain layer we have a repository interface we have an interface over here because domain layer doesn't get into the details of how the things work behind the scenes all of that is done in the data layer but the data layer is independent of domain layer so use case cannot directly call the remote data source or use case cannot call directly the repository that's mentioned in the data layer that's why we need to have an interface over here and the actual implementation in the data layer and then it will get into all the lower level detail like calling the remote data source or the local data source depending on the internet connection if youve still not understood it don't worry when we get into the code I think you'll have a better understanding we'll also have this diagram by the side which we'll constantly refer to to understand better for those familiar with solid principles all of the five solid principles are followed in clean architecture if you're not familiar with solid principles you can watch my 30 minute video on it let's see how solid principles are used in the clean architecture so in the domain layer in the repositories part we have interface segregation and that's because we're creating separate interfaces for separate task for example we have I user repository and I item repository two separate interfaces for two separate tasks in the domain layer we have entity and in the data layer we have model I said that entity is basically a model right because both of them are going to have the same properties they're both referring to the same object so the user model in the data layer is going to extend the user object in the entities of domain layer and this is Lisk of substitution we'll be following Lisk of substitution and I'll point it out when we do it what Lisk of substitution means is that this user entity can be replaced with this user model at any time and that's what we're going to do to follow clean architecture so that's very important in the use case of the domain layer we have open or close and single responsibility principle that's followed open or close principle is followed because the classes that we going to create in use case are going to be open for extension but closed for modification that means we'll be able to add new features in our application so we are open to that but we'll not be modifying any other file and that's because we are going to create separate files for separate task for example you can see over we have find user by ID and find ID items if we have a third feature in our application let's say find item by ID that's going to be present as a new use case in a new file that way we following open or close principle it's following the single responsibility principle because it's only going to have one responsibility to follow the last principle is dependency inversion and dependency inversion is used when we are segregating between the domain and the data layer the entire Repository part that I mentioned where we have to create a repository interface in the domain layer and the actual implementation in the data layer is a part of dependency inversion because dependency inversion means the strategy of depending upon interfaces or abstract functions and classes rather than upon concrete functions and classes and our use case over here is going to depend on the interface that's present in the domain layer not the actual implementation present in data layer we'll also be following the dependency injection which is a design pattern not a part of solid principles and we'll talk about dependency injection when we get to it now let's get started with our first feature authentication initially we're going to start working on the signup feature so that the users can create their account so let's get back to our code and start designing the sign up page the first thing I'm going to do is remove the boilerplate code from the main. do file so I'll scroll down and remove the entire homepage stateful widget from the app once that's done I'm also going to remove the comments that I can see after doing that we see in the home property of the material app we get an error that's because the my homepage class doesn't exist anymore I just removed it so to fix it what I'm going to do is create a signup page in another file and import it over here and replace it with my homepage so let's do that I'm going to open the file explorer in the lip folder I'm going to create my folder structure but how is the folder structure going to look like well the thing is different people have different implementations of clean architecture the one I'm following is the feature first approach the feature first approach organizes functionalities based on the features of the app to ensure clear organization and independent development of features so in this structure each feature will have its own folder and will include all of the code so the layers that we saw presentation domain and data the rule of thumb for this type of approach is that if you decide to remove a feature from your app you can simply delete its folder and it shouldn't cause many errors in the rest of your application so in the lip folder I'm going to create the features folder and after that I'm going to create my first feature which is O and in O as I said we going to have our three layers presentation domain and data so let's create them presentation data and domain now since we need to design our signup page I'm going to go into the presentation layer and create a folder known as pages in presentation there are three subfolders pages then we have wigets and then we have our block but we'll create block later on when we add it to our application now in this Pages folder we going to have our signup page so let's create that really quickly I'm also going to minimize this Explorer and have the full screen for the signup page now writing all the boilerplate code from scratch for flutter is a hectic task so what I'm going to do is suggest you to install an extension which is flutter widget Snippets once you install this we can quickly write some of the boiler plate code in flutter so assuming you've installed this I'm going to go ahead and create a state State full vidget here the signup page or the login page are going to be stateful widgets because we going to have our text field controllers in it and whenever we have text editing controllers we want to dispose them and dispose method is only present in stateful widget so let's go ahead and create a state full widget here you see I get an auto suggestion I'm just going to click on this and then type in sign up page with this my sign up page is now created now instead in of putting a placeold over here I'm going to return a scaffold and I'll then take this sign up page and return it in the main do. file so that I at least see some kind of output now I'm just going to restart the entire app come over here and you see it's entirely blank that's good we only have a plain scaffold so this is an expected output the next thing I want to do is remove this banner and change the name of my app over here so I'm I'm going to name this blog app and to remove the banner I'm going to say debug show check mode banner and set it to false once I do this the banner is gone from the side beside me I have a picture of the design we want to achieve to design this there are a couple of things we need to do first as you can see the background over here is kind of black and over here it's white we need to change that now those who are very familiar with flutter would obviously know that in scaffold we we have a property called background color using which we can set the color but the problem with that is that it will only change the color in this signup page however our entire application is dark mode so I don't want to write background color in every single scaffold instead I want the background color to automatically be of the black color to do that I'll have to set up the central theme in the main do do file as it's done over here to do that obviously ly I need a set of colors to follow and just so that we don't waste much time writing colors in our application what I've done is provided a link to all the colors that are present in our application you can just copy this entire app pallet class and paste it in your flutter code so what I'm going to do is open the file explorer in the lip folder I'm going to create a new folder you see we have the features folder here but outside of the features I'm going to have a core folder now this core folder is going to contain all the resources that are shared across the entire app so anything that's present in core folder can be shared across multiple features in our app and theme is one such thing it's not dependent on just one feature it's not just Au related theming is for the entire app it should be shared across the entire set of features and that's why we going to put it in core so in core I'm I'm going to create another folder called theme and in this theme folder I'm going to create a file let's call this app pallet do Dot and then I'm going to paste my app pallet class now obviously we need to resolve the import issues so let's quickly do that now if you're wondering how I got the autofix menu I just pressed command full stop and it popped the autofix menu now the next thing is to set up the theme we have all our colors with us now we only have to set up the theme so I'm going to take this and move it into a file of its own so in the theme folder I'm also going to have theme do do file and this theme do do file is going to contain the entire apps theme so first of all I'm going to create a class app Theme over here and then I'm going to create a static variable called Dark theme mode and that will be equal to this but you see if we just do this much it's again going to be light mode it's not not exactly dark mode so to fix this what we can do is remove everything and then type theme data do dark and as you can see it automatically Imports the material do. file now with this our entire theme of the app is also doc now I'm just going to go to the main. do file and here I'm going to pass in app Theme do Dark theme mode once I do this and I'm also going to save my sign up page restart the entire app and as you can see it's entirely dark mode now but the color over here isn't matching the color written over here so to fix that I'm going to go to the theme. do file and here I'm going to say do copy with so whatever properties and colors are mentioned in theme data. I want them to remain as they are but I also need to change a few things so I can say I want to change the scaffold background color to what well the color is mentioned in the app pallet file the background color so I can just take that background color over here app pallet do background color and after that I'll restart the app again and as you can see the color looks much similar now the next thing I want to do is go to the signup page and add the sign in text so I'll quickly do that by going to the signup page then in the scaffolds body I'm going to have a column viget because there are multiple children laid down vertically so in the column I'm going to pass in the children and the first child that I want to pass in is a text so I'm going to pass in a text over here and then I'm going to say sign up once I do that the sign up text should show up that's pretty cool the problem as you can see is the sign up is in the corner I wanted it to be in the center laid out perfectly so to do that I'm going to go in the column and add a property of main axis alignment as main Axis alignment. Center so from the main axis the main axis is the vertical portion from that it it is perfectly centered after that I want to increase the height of the text so I'm going to pass in style texttile and then pass in the font size as let's say 50 once I do that it's now bigger now I just need to Bow this so I can pass in font weight as font weight. bold once I do this as you can see they look pretty similar now the only difference is this is sign in and this is sign up but both of them look pretty similar the only difference is that the fields are a bit different in sign up so this is how the signup page looks like the next thing I want to do is add these or Fields And if You observe closely these Earth fields are pretty much similar the only thing that changes is the hint text of the text field other things also change for example a password will have an obscure text and every single one of them is going to have a different controller but from what's observable the only the hint text changes so what I'm going to do is create a reusable component for this o field so that I can use it in every single one of my Au pages so in the Explorer I'm going to go to the widgets and create a reusable widget which is au field. do once I do that I'm going to create a stateless wiget here and I'm going to name this o field after that from here I want to return a text form field we'll be returning a text form field instead of a text field because our entire sign up page is a form we'll be using a form to validate our entire signup process so it only makes sense to use a text form field not text field because it provides something known as a validator which which will help us later on but as of now let's get to designing this text form field so the first argument that I'm going to pass in the text form field is decoration so let's pass in a decoration and it accepts input decoration and in the input decoration I'm just going to pass in a hint text now as we know hint text is different for every o field that we create because for one o field it's name for another it's email and for the third one it's password so it only makes sense for me to take from The Constructor so whenever we initialize the O field it gets initialized to the hint text that is passed when calling it so I'll take it from The Constructor final string hint text and then require this I'm also going to pass in the hint text over here and there we go now I'm going to take this or field and put it in the sign up page so here we just going to pass in our or field and make sure to import the particular widget over here once you do that you get the option to pass in a hint text so I'm going to pass in an email over here and let's see how it looks this is our email tab doesn't look that bad but doesn't look good either now the next thing I want to do is format this text field now here's the thing if I go ahead and decorate the text field over here it's not going to apply to every single text field that I create maybe in some other feature I want the same text field to be there so that my app looks consistent if I do it over here it's not going to work out because Au field is only there for the Au feature it cannot be used outside of the O feature so what can I do so that my text field have the same design to do that we can go in the theme and set up the theme for the input Fields so I'm going to pass in input decoration theme and pass in input decoration theme over here perfect after that I have to set my border over here so I'm going to pass in my border which is enabled border and then I'm going to pass in the outline input Border in that outline input border I need to pass in a border side because right now a border side has been created that doesn't follow the look we want so here I'm going to pass in my Border Side and then pass in the color the color I have is app pallet. border color and once we do that I'm going to save this entire file and if I come over here nothing changes in the email but if I restart and come back over here we have a nice border that's attached to our text field now the difference is that the Border over here is not as thick as the Border over here so I'm going to change that by going to Border Side and changing the width of the border to let's say three I'll have to restart my app and when I come back this looks much better the next thing I want to do is increase increase the content padding that's present over here so I'm going to go to the input decoration theme and here we have a property called content padding and then I'm going to pass in Edge inserts. all 27 so that a padding of 27 from all the sides is per 10 and again I'll have to restart the entire app and when I come back this looks good the next problem I can see is that this border radius of the border is not good I want to make it more curved so I can increase the Border radius by going to the outline input border below Border Side I can pass in Border radius and then pass in Border radius dot circular 10 once I do that I can restart my entire app and this looks more curved and it also looks better and now our text field looks pretty similar to the one that's present over here but if I click on the text field you can see all the design that we had for our text field is now gone on now how do I fix this to fix it we need to understand why this error occurred in the first place this error occurred because we had only said the enabled border over here we not set what would happen if focused border was there enabled border only works when you're not clicking on anything and focus border comes into play when you click on the text field so for Focus border we' have not mentioned anything and that's why it goes back to the default border that it had so now I'm just going to copy this entire thing and put it inside of focused border but instead of repeating elements what I'm going to do is store it in a variable inside of app Theme so I'm going to have static final border which is equal to this particular thing and I'm also going to make this private so that this border cannot be used outside of this class or outside of this file that's how private variables in dot work and then I can pass the Border over here the same thing I can do over here then I'm going to save this also put a const over here restart the entire app and there we have our email this looks good but here's the problem whenever I click on the text field it's as it is I don't want it to stay as it is whenever I click on it I want the Border color to change that's it just the Border color to change to a pink color to do that I'll have to edit this the thing I'll have to do is first convert this variable into a function so I'm going to put parenthesis I'm going to have an arrow and then I'm going to remove final keyword with this this is now a function and in this I'm going to pass in the color that it requires so this color is the only part that's going to change right so I can just take the color from the parameter so what I can do is color color and ask it from the parameter however I don't want to be be able to add border as an argument every single time if I don't pass any border I want it to take the default value of the Border color so to fix that what I'm going to do is copy this put a square bracket beside the parenthesis and set it equal to this color so if we don't pass any color it's going to take a default value of the Border color and then I'm going to pass my color over here and as you can see it's an invalid constant value so I'll have to remove this constant and then here to resolve the errors what we can do is just pass in Border like this and if I save it restart the entire app we won't see any difference and that's because we have not specified the color in the focus border part so let's pass in the color the color that we want is mentioned in app pallet. gradient 1 if I do this and save I'll restart the entire app and there we have it but this color looks too strong so so what I'm going to do is change it to gradient 2 restart the app again and if I come over here this looks good enough so that's my entire text field with a reusable function created over here now what I'm going to do is go to the sign up page again and now I'm going to leave a sized box space of let's say height 30 because I want to leave a space between the two this looks better then we have let's say our name text field then I'm going to copy this paste it again then there's going to be email then I'm going to paste this again and finally we're going to have password then I can save the entire thing and we have three text Fields but they're stuck together so what I can do is leave a size box height between all of these text Fields so just like this I'm going to copy it but this time it's going to be a height of 15 not 30 then again we're going to have a height of 15 then I'm going to come back over here and this is how it look looks not bad the next thing I want to do is add padding over here as you can see there's some space left over here from the sides I want to do the same thing now one solution is to wrap every single text field with that padding but that can be quite cumbersome right so to do it more easily what I'm going to do is wrap this entire column widget with a padding widget so that means all of the children will have to follow that padding so everything will be leaving a space from the side so I'm going to press control shift R from my Mac so that these options appear and then I'm going to wrap this with a padding widget if you don't see that menu what you can do is right click click on refactor and then you'll have the set of options then we are having a padding with Edge inserts do all 15 so let's put that and there we have our entire application looks good enough and as you can see the highlighting also works really well the next thing I want to do here is create this button and I'm going to create this button in a separate vget as well because this button can take a bit of a work because we need a gradient button to be present and that's not present in the elevated button so we'll have to do a work around so let's open the Explorer and in the widgets I'm going to create o gradient [Music] button do do file then I'm going to minimize this tab again and then I'm going to create a stateless viget again I'm going to call this Au gradient button and then I'm going to return an elevated button from here then the onpress is as of right now empty and the child is a text which is going to say sign up now I can take this all gradient button and put it in the sign up page so here I'm again going to leave a constant sized box of height let's say 20 and then we can pass our o gradient button over here make sure to import it at the top then I'm going to save this restart the entire app and we have our nice little button showing up here now there's a lot of things to change here first of all I want to increase the height and width of this button so to do that in the O gradient button I'm going to pass in the style which is going to be elevated button do style from so whatever default properties are present in elevated button I want to take that and style using the custom properties that I mentioned over here so the first thing I'm going to change is the fixed size so what is the size of this elevated button and this fixed size takes in an argument of size so I'm going to pass in size like this it first accepts a width and then a height the width for my button is let's say 395 and the height as 55 then I can put a const over here save it and there I have my button looks solid the next thing I want to do is change the color on this text so when I have my text over here and it's giving me a warning here and if you're wondering how do I have inline warnings that's because of an extension called error lens so you can go ahead and install this extension on vs code and and you'll get this inline warnings so it's saying that we have this error because the child argument should be at the bottom of widget Constructor invocation that means whenever we have elevated button the child should be the last thing that's present over here so we can pass in a constant text sign up here now we want to increase the font height of this text to do that I'm going to have style text style then pass in the font font size let's say the font size is 17 the font weight is font weight. w600 it's not exactly bold it's very close to bold bold is w800 I've set in w600 the next thing I want to do is implement this gradient now the problem here is the elevated button doesn't give us the option to pass in a gradient that's just not allowed so what we can do is wrap this elevated button with a container widget in container we have the decoration property where we can pass in our box decoration and in box decoration there's a property called gradient this is where I can pass in my gradient and there are various type of gradients right the one I want is a linear gradient if you want you can search up for other types of gradient but that's what I want I have one color over here and it changes to another color over over here so I'm going to have constant linear gradient and then we need to pass in a list of colors so I'll pass in the list of colors like this now what is my list of colors well it is app pet. gradient 1 and then there's app pallet. gradient 2 now if you want you can pass in app pallet. gradient 3 but in my opinion app pallet. gradient 1 with gradient 2 looks better then all of these three combined so I'm going to comment this app pallet gradient three if you want you can put it in and that should have a gradient on our button now if you're wondering why didn't we set all of this in our theme the reason for that is that gradient is only needed for this one particular button not all of our buttons are going to have gradients so we don't need to add this to our Global theme Global theme is only for things which will be repetitive throughout our entire app this gradient button is a one-time thing so anyways let's get back to our app and here we see this is a funny looking picture you see we have a gradient showing up so something happened but it's not giving us the button we wanted why that's because in the elevated button it already has its color right so it's putting its color but then in the background we also have this container so this color is hiding this background so how do I make sure that this button doesn't have a color of its own to do that I can just do background color as colors. transparent and if I do this much there we have our button showing up now if you want you can take this colors. transparent and move it to app pallet so I'm just going to create static const color transparent color which is equal to colors. transparent now if you're wondering why did I store all the colors in a separate class of its own that's because this way I have a centralized control over the colors in my application that means I have only one place to go and all my colors can change the entire look and feel of my app can change so if I want to change the background color I can do it from here and it will affect all the places where this background color is being used so that's a pretty powerful solution if I use this in every single place let's say all of these colors were scattered around the entire app and then I wanted to change the background color or the gradient one color then I have to go into every single file and change the color that's a pretty bad solution because once we have let's say 20 classes where this gradient one is being used it's going to create problems right one place I'll forget to add the gradient one one place I'll forget to change the color one place I will change the color so it's going to be messed up so this is a centralized control of the entire colors part now coming back to our o gradient button I can pass an app pallet do transparent color restart the entire app and there we have it it doesn't look very good yet that's because we can still see the background of the button to remove this what I can do is set the shadow color to colors. transparent with this The Shadow of the button will be set to transparent and actually I need to set it to app pallet. transparent color and when I come back you see that's my button looks pretty good the only problem is that the gradient is not followed as it's shown over here and that's because I've not set the beginning and ending of this linear gradient so I can pass that in after the colors is passed I'm going to pass in begin and then it requires alignment so I'm going to pass an alignment dot bottom left so it's going to begin from bottom left and it's going to end at alignment dot top right and now this looks much similar to this the next thing I want to do is change the Border radius over here this is more curved than over here so then I'm going to pass in Border radius and it's going to be outside of this gradient because it's a box decoration property it's not a property that's present in gradient so I'm going to have border radius do circular and then pass in let's say seven once we do this that's our solid looking button pretty cool so we are almost there with our entire app the last thing that we need is this text don't have an account sign in so let's quickly create that I'm going to go to the sign up page and then pass in size box of height 20 and after that I'm going to pass in a rich text over here the rich text is going to have a text argument and here we need to pass in an inline span I'm going to pass in a text pan over here and then the text pan is again going to have a text and that's going to be don't have an account that's what the text is going to say now what is this Rich text and how is it different from text the thing is that we have some text over here which is written in one style it is having a white color and then it has a text which is written in another color Rich Text will allow me to create two texts that are in the same line with different text Styles so I can pass that in now the problem here is first of all the font size is pretty low so we have to change that and after that we also need to add this single inverted comma so to add a single inverted comma I can just pass in a single inverted comma but it breaks the entire string to fix that what you can do is wrap this and entire string with double inverted comma but another solution you can take is just passing a backslash over here the backslash is going to treat this inverted comma as an inverted comma not the end of a string and then if I come back I have don't have an account text written as I wanted now I need to increase the height to increase the height I can pass in the style but I'm not going to do it the usual text style way what I'm going to do is take use of the default text styles that flutter has provided us with so I'm just going to pass in theme do off context dot text theme do title medium once I do that it's going to take the title medium that is defined by flutter by default and set it as the style of this text ban and as a result of this don't have an account text looks much bigger the next thing I want to do is create a sign in text over here so to create that I'll have to go inside of the text man and pass in the children argument this children is going to be a list of inline text pan so I'm going to pass in a text pan again which looks pretty similar to the one we created above the only difference is that the text looks different so we have sign and written over here and after that we also need to set a style so that this text pan has the same height as this thing so I'm just going to copy this entire thing and paste P it over here simple now I can come over here and that's how it looks now we need to increase the spacing between the two so what I can do is leave a space here and once I do that you see this looks good now I just need to change the color of this text to do that what I can do is pass in the dot copy with method that's present over here but this gives us an error the error says that the method copy withd can't be unconditionally invoked because the receiver can be null that means this title medium is a text style that can be null and on that I'm calling copy with the copy with method is only there on texttile not a texttile that can be nullable so to fix that what I can do is pass in a question mark meaning that if it's nullable don't call the copy with method and if if it is not null then call the copy with method so in the copy withd I can pass in the color let's say my color is app pallet. gradient two just matching with this style okay both of them look pretty similar but this doesn't look as good as this one and that's because we have not bolded the font so let's do it font weight do bold once I do that come over here that's how the entire app looks and that's pretty good I'm satisfied with this now let's just improve the formatting over here let's put some const to remove the warnings so I need to put a const everywhere to put const on every single line what you can do is use multi-line cursor to use multi-line cursor what you can do is press option if you're on Mac and then select the lines you want to add const to so these are the lines where I'll add const to and then I can pass in const with this const is added on every single line I selected with this I'm going to save and that's my sign up page that looks good now there's a lot of refacing that's still left but we can look after that later on the next thing I I want to do is set up the form for the signup page so to do that I'll have to go to the signup page and in the signup page I'll have to wrap my entire column with a widget known as form this form widget is going to validate the entire thing and it's going to convert it into a form now what I want to do is pass in the key to this form and this is not any key that you can pass in like a unique key okay what we need to pass in is a special key over here and that's going to be final form key of the type Global key and the global key also accepts a gener the gener over here is a state state full viget that's not what we want we want to create a global key of the type of form State So This Global key is going to contain the form State then I can take this form key and pass it in over here the way form works is that it's going to look into its descending wigets so it's going to see column text then it's also going to see o field the O field contains a text form field and whatever text form Fields have it will validate that and to validate based on a condition we'll have to go into the O field and here add a new function that we talked about which is valid dator this valid dator gives us a string argument and based on that we can validate the entire text form field now here we going to check if the value is empty or not so if the value is empty what does that mean that means that the User submitted the form without passing in any content inside of this text field so I'm just going to say that hey you've forgot to put in the content in this field so I'm just going to say dollar hint text because hint text is going to say what field it is is it a name field email or a password field so we're going to say hint text is missing there we go now what should happen if the value is not empty that means everything's all right then we have to say that hey there's no error everything looks good to us so we'll return null and that's our entire validator that's all we have to do now whenever the user clicks on the button what we need to do is use this form key and validate the entire form so if you check there's something known as form key do current context or current state you can use either of them dot validate once I call this method it will validate every form field so it can be a text form field right that is a descendant of this form and that truly is so we're going to be all right when we do this now we can only do this when the user hits on this button right we cannot do this in the init State because think about it the user comes on this screen and suddenly he just sees a bunch of Errors that's not what we want whenever the user clicks over we'll valid is any of this text missing if any of the text is missing we're not going to continue forward and we're going to throw out error over here now to do that we'll have to start making calls to our repository because whenever we click on a sign up we want to create a new user in our database now all of that stuff will be done later on but first I want to focus on this part name email and password you see we can type anything inside of these fields and it will be all right but here's the problem we won't be able to access the value that's present inside of these text fields to access the value we'll have to create a text editing controller for these text Fields so let's quickly create three text fields for each one of them so I'm going to create final email controller which is equal to text editing controller then I'm going to take this line and paste it two more times the second line is going to be password controller and the third one is going to be name controller now whenever we create a text editing controller we need to dispose them off so let's quickly do that so I'm going to pass an email controller. dispose password controller. dispose and name controller. dispose now I've called super. dispose after disposing all of this because that's how it's done we'll dispose everything we have and then let flutter dispose rest of the remaining stuff now what I need to do is take this email controller and attach it to this o field so it only makes sense for me to go into the O field and accept a text editing controller from the argument so I'm just going to take this controller and require it I can also pass in the controller to the text form field so there we go and in the sign up page you see we have three errors to fix those errors what we can do is put a comma here pass in the controller and pass in name controller and as we can see it gives an error invalid constant value if you're passing in a controller that's not a constant so we'll have to remove a constant from here and the same goes for these two Fields so let's quickly remove it for them as well now I can again pass in a controller here and pass in the email controller again a controller password controller that looks good now if I come back nothing really changes over here but now we can get the values that the user passes in using password controller. text or email controller. text that's nice but another problem that I have is when I type in a password you see it manually displays it to me password shouldn't be that way it should be an obscure text that means it should have a DOT instead of the characters written over here to do that I can again go to the O field and here I'm going to have a final buol is obscure text and then I can require it from The Constructor but why would I want to require obscure text every single time I can just make it this way right I can just take this obscure text and set it to false by default so if the user doesn't say anything it's going to be false that means the text is not obscure however the user has the ability to change it to true and if they change it to true it will be obscured so here I can just pass obscure text as equal to false and obviously this dot is obscure text now here I can go ahead and pass an obscure text and then it requires a Boolean value so I can directly pass is obscure text if you want you can name this is password so that it makes more sense to you obscure does make sense to me so I'll just keep that now in the sign up page you see we don't get any error however we have the ability to change the property is obscure text so in the password I can set it to True restart my entire app and as you can see whenever I pass in it's a DOT now if you want to change this obscure text the O field does have a property to change that so you see we have obscuring character here you can change that by default it is this thing if you want you can change it to anything else however I do like the dot that's by default present over here so that's kind of everything I had in the sign up page now I can take this entire design and clone it for sign in page which looks very similar we've already seen that in this design right all I need to do is remove this name text field we only have email password change the text over here change the text over here change some text over here and there we go that's all we need to do but before we go there actually I just realized in the signup page we have asked don't have an account instead it should be already have an account then we want to sign in okay now that we have the sign up page with us we can close all the save files open the file explorer and here create a new page and let's call this loginor page. dot in the login page everything's going to be very similar to sign up page so I'm just going to select everything command a copy it and paste it over here here then I can minimize the Explorer go up and change the naming so we have sign up page everywhere right so I can take the sign up use multi-line cursor using the option button and then change it every single place now I'm going to call this login page and this way this is a login page class simple I'm also going to remove the name controller because when the user is logging in they don't have to pass in their name so here in the dispose it's going to be just email and password controllers that I'm being disposed off after that I can scroll down and here instead of saying sign up I can say sign in again scroll down remove the name controller and also remove this height 15 we only have email and password then here we say don't have an account and then pass in the back slash so that this treats it as a normal single inverted character and then here we can say sign up simple now I need to see this login page right to do that I'll have to go to the main do do file a quick way to navigate in Visual Studio code is to press command plus P once I do that I can search files by name so I can pass in main do Dot and then hit enter this way it easily opens up main do. file for me then instead of passing in sign up page I can pass in the login page and by default login page is the one that I want so I can remove the sign up page from here simple then restart the entire app and there we have it the signin page with email and password text Fields with sign up written over here not sign in that's something we need to fix and followed by we have don't have an account sign up now how do I change the text of this button to do that I'll have to go to the O gradient button and here when we pass in the text we can ask this text from The Constructor so what we can do is final string button text and ask it from The Constructor so we have required this dot but button text then I can take this button text and put it down over here also make sure to remove the cons from here and put a cons for the Tex stle that's it now login page and sign up page both gives give us an error and that's because we need to pass in the button text so let's pass it in the button text here is going to be sign up and the login page is going to have a button text that says sign in okay that looks good the text is now changing the next thing I want to do is whenever the user clicks on the sign up text they should go to the other screen to do that we'll have to to set up our navigation now for navigation if you're familiar with G router you can go ahead and use that if you want you can use named routes that flooder provides or you can just use the material page route normal Navigator option that we have I'm going to use that so what I'm going to do is wrap this entire Rich text with a widget and that's going to be a gesture detector so that whenever the user clicks on this they go to the other screen so we're going to pass in an on tap and the on tap is going to have a function now we need to navigate from this login page to the signup page whenever the user clicks on this text so we can do Navigator do push context and then we need to pass in the route the route is going to be material page route then we have to pass in a builder the Builder is going to be a context and then we need to return a widget the widget that we want to return is sign up page because that's where we trying to go then we can put a const over here now I can restart the entire app and now when I try to go to the sign up page I can go there but here's the problem I have to write this big thing whenever I have to navigate from one page to sign up page what if I ease this process a little bit what I can do is control X this particular part of the Navigator do push function then go to the sign up page go at the top and here create a function called Static route and return this particular thing now whenever the user wants to navigate from one page to signup page what they can do is signup page. route this way they're able to go from one page to sign up Page by just using this simple thing it's quite reusable and we don't have to type this big thing every single time and one day maybe you decide that you want your own custom route to be present not Material page route or copertino page route maybe your own route so you can just change it over here and it will reflect in all the places now I can restart the entire thing and it should work as expected now I have to do a similar thing for the signup to login page navigation to do that I can go to the sign up page copy this route paste it over here also there's an unnecessary import we can remove that and here we can return a login page then I'll scroll down we have a gesture detector I can copy this particular line go to the sign up page again scroll down wrap this Rich text with a gesture detector widget and whenever the user clicks on this text what we need to do is navigate from sign up to login so I can just say login page do route now if I restart the entire app I can go to the signup page I can go to the signin page there we go now the next problem I have is that whenever I go from sign in to sign up page there's no back button displaying over here what can I do about that what I can do is on the signup page I can add an AB bar property okay I'll just add an empty AB bar so that I get access to this particular tab okay now the problem is that this AB bar doesn't match with the color that's specified as the scaffold background color so to change this what I can do is go to the theme right so I'll press command P go to theme do Dot and here I'm going to pass in abar theme and the abar theme is going to be this particular class which will allow me to pass in a background color and my background color is this app pallet. background color I can also pass in a const here like this I can restart the entire app and when I go to the sign up page next you see this looks good and I also have a back button which I can click on to go back the signin page doesn't have this back button because when the user comes on this page what's the purpose of showing them a back button the login page is the first page the user will land on if they see a back button they're just going to be confused so that's the entire design of the authentication Pages the next step we have to do is start working on implementing the functionalities of the app so whenever the user clicks on sign up we need to make sure that the user is created in our database so let's get started with that to get started what I'm going to do is close this theme. do file open up the file explorer and then close the presentation layer we are done with the presentation layer for now we still need to add block but we'll do that later on now let's get to the second layer the domain layer the domain layer in clean architecture is considered the most stable layer it is considered the most stable layer because it is the innermost layer and does not depend on any other layer it contains the Core Business logic and the rules of the application which are less likely to change compared to the details of the outer layer so data and presentation can keep changing because the user interface and the way we are fetching the data or our database can keep changing but the bore business logic is very less likely to change also domain ler defines abstract interfaces or contracts without concerning itself with how these interfaces are implemented these interfaces are implemented in the data layer if we go back to our diagram we see this repositories part right I told you an abstract interface is created in the domain layer and its implementation is created in the data layer layer so domain layer doesn't care how this interface is implemented in the data layer it just cares that this repository interface is present this is an advantage because both the layers are now decoupled by decoupled I mean if there are some changes in the data layer it's not going to affect how domain layer Works decoupling is often achieved from separation of concerns and that's what we're doing here if you're still wondering why do we have a repository interface in domain layer and a repository implementation in data layer why can't the data layer repository directly talk to the use case why can't we just remove the repository interface that is present in the domain layer and that's a good question the reason we can't do this is because of the principle of separation of concerns in clean architecture we know that the domain layer is the innermost layer and the domain layer should not depend on any other layer so if use cases has to call the repository that's present in the data layer the domain layer is depending on the data layer and that is a problem we can't allow that domain has to be independent from data so what we do is introduce a repository interface in the domain layer now use case will depend on the repository that's present in the domain layer and the actual implementation will be in the data layer this is the most important concept to understand in clean architecture if you understand this it's going to be all right so assuming you've understood let's go ahead and in the domain layer create a folder called as repository and in this repository we're going to have a new file and let's call that Au repository dot dot I'm also going to minimize this Explorer and now over here I'm going to write my interface the Au repository interface so you can call this abstract class but since 3 has come out we can use abstract interface class that would make this a true true interface and then I can pass in AU repository like this now if you're wondering what is the difference between abstract interface class and abstract class the difference is that abstract classes are used to provide a base class for concrete subclasses to inherit from interfaces that is abstract interface are used to define a set of methods that a class must Implement and that's exactly what we want we want an interface to be present here which will force the classes implementing this interface to have a set of methods that we Define here and what are we going to Define we're going to Define two methods sign up with email and password login with email and password now what is the return type of this function going to be well there are two outcomes for that it can either be a failure or it can be a success I want to get both of them in this Au repository Au repository isn't just going to throw out an error message which can cause our application to crash instead there should be an easier method to do so and that's why we'll be using an FP do package over here so if you go to Pub dodev and search FP do you'll see this package you can copy this go to the pope.l file scroll down and in the dependencies add this particular version and then save it make sure the flutter Pub get is run and then you can close the pubs spec. yaml Now using FP do what I'm going to do is specify what the return data type should be well it can either be a failure or a success right so I'm going to specify either year that comes from the FP do package what either allows me to do is either specify a failure or a success so what should be the return data type if it's a failure and what should be the return data type if it's a success if it's a failure what can I even return I can either return a string or something else it can actually be any data type I want so what I'm going to do is create a separate class for this called failure that's because I don't only want a string to be returned when there's a failure maybe I also want to return a status code maybe I also want to return the error stack that I get all of this can't be put into a string right that's why we're going to create a custom class for this so you can go ahead and open the file explorer in the core folder we're going to create our failure class why core because this failure class will be used in almost every single one of our features whenever we use FP do and we want to return a failure we're going to return this class so it cannot be something that's created inside of the O feature we have to do that inside of the code core folder so I'm going to create a new folder here and let's call this error so whenever an error occurs what all stuff we need here and in that we going to have a failures. do file in this failure I'm going to create my class failure and it's going to be very simple for now it's just going to have a message it's not going to have anything else just a message is fine with me and then I'm going to create a Constructor for this failure class and doing just this much is fine you can stop here but what I want to do is just in case I don't pass any message I want it to take a default value that hey an unexpected error has occurred so you can pass in square brackets over here which allows me to pass in a default value for the Constructor and then I can say an unexpected error occurred doing this we have our failure class setup now I can close this file and over here I can first pass in Failure make sure to import this from the failures do do file so in either the first thing has to be the failure what is the failure return data type and the second has to be a success now what should be returned when there's a success in that case we'll have to return a user model a user entity that we'll create but for now we can just pass in a string later on we can update this but for now we're just going to have a string over here and then I can create my function let's call this sign up with email password and then there we go but just doing this much isn't enough because whenever we sign up we get arguments like name email and password so let's take that from the parameter over here what I'm going to ask for is required string name required string email and required string password so with this I have my function declaration created but that's still not enough that's because whenever we try to connect to super base and get data from super base it's going to be asynchronous so we need to wrap this entire thing in a future so let's do that we can do future followed by either failure string so that's our entire return data type and we can do the same thing for login with email password two so we can just have future either failure string it's still going to remain the same and then login with email and password and this time we're not even going to ask for the name because when we login we just have email and password there we go so that's our entire interface for Au repository class sure we still have to change the success part over here because we're not going to return a string what we are going to return is a user entity object but we can can get into that later on first let's just connect our app to superbase get some data from superbase let's upload some data to superbase and then we can update this part so naturally the next step is going to be to set up the super base account so to do that go to this website superb.com once you do that you have to click on start your project once you do that it's going to ask you to sign up or sign in since I already have an account I'm quickly going to sign in however if you want to sign up and create a new account you can do it right over here it's a pretty simple process so I'm not going to cover it I'll directly see you after logging in so after you've signed in successfully you're going to see a page that looks like this obviously you're not going to have a project over here you'll have to create a new project I already have one for the demo I had created earlier now I'm just going to click on this button new project then I'm going to choose the organization over here then it asks me for the project name and the database password make sure to remember your database password I don't think it would be useful when using flutter however I recommend you to remember it so I'm quickly going to pass in the project name and the database password and I'll see you after I've done that after your project is created and set up by super base you should see a screen like this we'll configure stuff over here later on but first thing I want to do is connect my app to the super base to do that I'll have to use a package that that's present on pub. deev and that is super based flutter package so I need to use this package to get my stuff done now you can copy this or another thing you can do is press command shift p if you're on Mac OS then click on do add dependency and then pass in super base underscore flutter over here it will automatically install the latest version of superbas flutter package in your program after that's done we need to initialize super base so to do that I'm going to open the file explorer go to the main do. file scroll up and here I have the main function I have to make this main function asynchronous because to initialize super base I'll have to use AIT so I'll do AIT super base and then make sure to import the super base flutter package dot initialize once you do that it will ask you to pass in two things URL and Anon key so let's pass it in over here URL and Anon key now how am I going to get the URL and the Anon key both of them to get it I'll have to go to my dashboard scroll down and it's present over here project URL API key or Anon so I can copy this and paste it over here but I'm not going to do that what I'm going to do is store it in the core folder so in the core f folder I'm going to create another folder called secrets and in that secrets I'm going to create app secrets. file now if you want you can call this superbas secrets. file to be more specific but I think this one is enough for this application then I'm going to call this app Secrets class and then I'm going to create a static const super base URL variable which will store this value the reason I'm doing doing this is so that I can get ignore this particular class so that all my secrets are not stored on GitHub when I upload them and again I'll have a centralized control of where my superbase URL is now make sure to use your own superbas URL don't use mine because I'm going to delete this project soon after the video is published now in the URL part here I can do app secrets. superbase URL and then in the Anon key I again need to to take the Anon key go to app Secrets class and then create a variable static cons super base and then key and that should be equal to this particular line and I think Anon key is just a single n now I can go to the main. do file again and use app secrets. superbase and in key save it and there we go now this superbase do initialize is going to give us super base which can be really helpful later on because we'll have to access Super base. O or superbase do database so all of that comes from this particular super base that is returned by the initialize method so what I'm going to do is store this in a variable super base and then I can pass it down to my app and reuse the super base variable however that's not the point now so we can just assume that the super base initializing part is done however we'll rerun the entire app and see if there is any error so I'll quickly run it on iPhone simulator I'm also going to run it on Android emulator because if there's any issues it's going to let us no and we can fix that so the app successfully runs on Android and iOS however I would like to make some changes first of all whenever we have an await call in the beginning make sure to use widget flutter binding do Ure initialize first because whenever you run run app it automatically has this part vets flutter binding do Ure initialized however when you run something before run app like await super base. initialize or Firebase do initialize you need to call viets flutter binding. insure initialized then call this so that the binding is initialized correctly and after that we can do our own processes it didn't give us any error but make sure to do this just just as a precautionary measure anyways now since this is done what we can do is close with main. do file I can also close the app Secrets file and now what I need to do is work on the data layer if I come back to my diagram we had presentation widgets part done then in the domain we have repository done I'm directly going to the remote data sources now authentication is not going to have any local data source I'm going to explain later on why but for now let's just get started with the remote data source so I'm going to go to the data and create a new folder data sources and in that I'm going to create a new file and let's call this Au remote data source do do file now you can call this o super based data source or o Firebase data source or any other database you're using I'm just going to call this remote data source because I only have one remote database connected after that I'm going to minimize the Explorer Tab and the first thing I'm going to do here is create an interface I'm going to create an interface for the auth remote data source as well so that whenever I have to change from super base to any other database I have a strict contract to follow and I don't miss out on anything so I'm going to create abstract interface class and let's call this Au remote data source after that I'm again going to create my two methods inside of this future string sign up and if you want you can call this sign up with email password and then require the same arguments that we did before require string name String email and string password with that we have sign up method created similarly we also going to have a login method and that's going to be called login with email password and here we're just going to take an email and a password no name awesome now I have my interface with me now I'm going to create a general class that will implement this interface so I can do Au remote data source and what should we call this Au remote data source is the same name as this one so I can just call this imple with stands for implementation so this is au remote data source implementation and that is is going to implement this interface that we just created once we do that you see this class now has errors and the reason for that is we have not created two missing overrides login with the email password and sign up with email password now if you're wondering why do we have to create an interface again we just did that in the repository section in the domain layer and that's true you did that in the domain layer for repository but you didn't do it for data source right and if you you see data source is returning a future string it's not returning FP do either failure or string it's just returning a string because in remote data source we are only concerned with calls made to the external database we don't want any other dependency inside of it we don't want any other plugins inside of this we only want superbase calls to be present over here the very basis of clean architecture is actually depending on interfaces rather than concrete implementation this way you don't have to care about the details that are present inside of something and you just depend on the contract that's present over here so with that I'm going to minimize this Explorer Tab and here I'm going to ask for the superbase client from the Constructor of this class so we're going to have final super based client super based client and we're going to take that from the Constructor let's also format all of these file that are present so I'm just going to press comma comma and press command s and it will automatically format it for me if you're wondering how the auto format is being done you can just go to the settings of Visual Studio code to do that you can press command shift p then type in settings and it will open up this tab preferences open settings UI then in the search bar you can type in save and you can scroll down to see editor format on Save just put a tick mark over here and make sure this is set to file if you want you can change the autosave delay over here but we're not using autosave we're using format on Save now we can close the settings now we can get started by implementing our own methods using super base but before doing that I think you might have a question over here why are we taking super based client from the Constructor why not just initialize it over here like this super base client and the reason we're not doing that is because doing this will create a dependency between Au remote data source implementation and superbase client so anytime we have to change our database let's say from superbase to Firebase there's a lot of things to do then so what we are going to do is use dependency injection by dependency injection I mean whenever this class is call we're going to inject super based client instance in over here and if you are familiar with unit testing you know that whenever we have external dependency we always want to create a mock when we are testing so doing this will help us mock the super based client and injecting it when we are testing so to summarize this is just for two reasons so that a dependency is not created between the class and super base and the second reason is for testing now coming back to our methods we have sign up with email and password that we're going to work on first so first first of all what I'm going to do is put in async over here and then I'm going to remove everything and start writing my method for signing up with email and password so what do I want to do whenever this method is called I want to create a user in superbase authentication by superbase authentication I mean if I go to the superbase dashboard and go to the authentication tab over here super base has built an authentication that we can use I want the user to be created and displayed over here now there are a lot of things you can do in this authentication tab meaning you can go into the policies and change the policies go to the providers and say which providers Allowed by default email is allowed and that's enabled to good for us but if you want to implement let's say Google signin you can enable it phone you can enable it and if you want to know how to implement these things you can check out the super based documentation which has listed everything we are going to be using email authentication and it's enabled by default so that's good for us if you want you can change the rate limits over here how many emails should be sent per hour from your project how many SMS should be sent how many token refreshes should happen I'm not going to touch anything over here and move to email templates if you want you can change the email template configure the URL check out hooks but I'm not going to do any of that what I want to do is very simple create a user using Super base. O so first of all I'm going to put in try and catch block over here so that if there's any exception I get access to them then in the tri block I'm going to have superbase client do o dot and you see using o I get a bunch of methods that I can use what I'm looking for is creating a user or signing up so I can look for a method that has sign up over here and there we go we have sign up up over here then you can pass in an email phone password whatever so I'm going to pass in my password which is password and then I'm also going to pass my email so my email is email and that's pretty much it we also have a name property but if you see signup doesn't have a property to add name over here maybe in your application you have other data like putting the user's date of birth putting the profile picture of the user but all of those fields are not present in sign up so what we can do is use this data property that we have this data property will help us store additional data of our user so I can just pass in a data like this and pass in the name so the name is name now if you have any other thing you can pass in like date of birth etc etc also a thing to mention here is to put this name in a single inverted comma if you just pass a name name what super base is going to think is that the key is the name of the user so let's say my name is ran so it will think the key is ran and the value is also ran and that's not what we want we want the key to be the name String and the value should be the name of the user so with this we have everything set up correctly now the sign up is of the type future so what I can do is await it to get a response so I have final response equal to Super based client sign up now what I can do is from here return response Dot and you see response has multiple things session and user session is going to give you multiple things here like access token token type expires that expires in and even user but we don't need any of that we are returning a string because we want to return the user ID now you might say that hey you've not mentioned any user ID over here where's the user ID going to come from and super base is automatically going to generate that ID for us and we can get that ID by just doing response. user do ID once we do that we will get access to the ID but we only want to do this if the user is not null otherwise it's going to give us an exception and we don't want that so I can just check over here if response do user is equal equal to null if the user is null then I'm going to throw an exception and what exception should I throw here I can pass in a string I can pass in the exception class but what I want to do is create my own custom class for this exception so I can open the Explorer go to the core because this exception that I'm going to create is going to be used in the block feature as well whenever we have an exception we're going to be using this particular exception custom class that we creating so in error I'm going to create exceptions. do as well then I'm going to create class server exception and this is going to implement the exception class that dot already gives us then I can create a variable final string message and then create a Constructor server exception this do message now the reason I've created my own server exception is so that if I have any more details like putting in the status code putting in the entire stack Trace I can do that but I'm not doing any of it if you want you can go ahead and do it this is just an extra precautionary measure that I've taken so I'm going to close this exceptions do do file and here I'm going to throw server exception and what is the message going to be if the user is null message is going to be that the user is null and this is obviously a const server exception in the catch block we going to do the same thing again we're going to throw a server exception again and this time the error message is going to be e.2 string so this is our entire sign up with email password function to recap what we did over here we're just creating a user in the super base authentication tabs so that a user displays over here whenever it's created then we get a response from here we're checking if the response user is not n that means that the user was null but that means some form of error has occurred so we're just returning a server exception saying that hey user is null and if the user is not null then we're just returning the user's ID and that ID was automatically generated by super base then in the catch block if any other exception occurs we're just throwing server exception what should we do next should we work on the login feature if you want you can but what I would would prefer is just completing the entire signup process so I let the to-do stay over here so that it gives me a warning and keeps a reminder that hey I still need to implement this login with email password function and what I can do is get started with the next thing let's see what we've done we have created a remote data source right now we do not have a model we create a model shortly but after the model we have repository the repository that was created in the data layer and we want this repository to implement the repository that was present in the domain layer the interface that we created so let's get started with that in our data layer we can go ahead and create a new folder and call this repositories again but in this repository we're going to have o repository implementation do do file this was just an interface this is an implementation of this interface then I'm going to minim miniz this Explorer and start writing the code for implementation so I'm going to create a class Au repository implementation and it is going to implement Au repository and make sure to import that from the domain layer now we get two errors because we need to create two missing overrides for them and it automatically Imports this either do do file we'll remove this import because what we want to import is the entire FP do. package now what this Au repository implementation is going to do is call the signup function from the auth remote data source so you might think of creating Au remote data source variable over here and you might be right we have to do that but we cannot directly create Au remote data source like this the reason for that is our Au repository implementation should not depend on AU mode data source like this we again have to do dependency injection so what I can do is just take this like this Au mode data source remote data source don't put all remote data source implementation over here because we don't want to depend on implementation we want to depend on the interface that we created depending on interface means that we don't care about how the implementation was done we just care if the method exists or not in our contract so now I can create Au repository implementation Constructor so I'll have this do remote data source if you want you can also make this class a constant let's also format this place now we not concerned with login yet we directly want to go to the sign up with email and password function and here again we're going to have an asynchronous method again we're going to have TR catch block the reason we are having try catch block again is because whenever we call remote data source SCE method over here like this one is going to throw a server exception we need to handle this server exception that is being thrown otherwise it will give us a runtime error that's why we have to wrap it with a try and catch block now in the triy block what I'm going to do is call remote data source Dot and we have the method sign up with email and password then we'll pass in the name email and password we're taking from the parameter and then that's pretty much it now this is going to return a future string so I can aade this and it is going to give me the user ID so I can just say final user ID is equal to this particular thing now if we get the user ID that means it is a success so to return a success you can't just return user ID like this that means you're returning a string so this does not conform to the bounds that are set up over here either failur string we need to return a string that says yes this is a success not just a direct string so to do that we'll have to return right from here and this right function comes from the FP do package and then we can say we returning user ID this return right means that hey this is a success and here's my string user ID value however if there's an exception then we want to return left that means there is a failure now instead of doing catch over here what I can do is put a specific exception that I'm catching on server exception and make sure to import the exceptions do do file over here what server exception does is give this e the type of server exception so that means if I do e do I'll get access to the message value automatically and that's a good thing I want that so anyways if there's a server exception what I'm going to do is return left and then I'm going to pass an e do message but doing this gives us an error the argument type string cannot be assigned to the parameter type failure you see earlier we had said that if it's a failure we want to return a failure class so that means I'll have to take this thing out and wrap it with the failure class and then as a message I can pass an e do message over here and that's basically the entire implementation of sign up with email password so let's go back to our diagram to refer where we are we have a repository created over here and that's a done process the next part is to use an entity and send it to use case right now we don't have an entity which we'll shortly create don't worry about it now directly we have to go to the use case and then after the use case we'll create a block and then test our application so let's go go to the use cases in the domain layer so I'm going to open my File Explorer again we'll close the data layer for now we are done with it so let's close all the save files in the domain layer I'm going to create a new folder called as use cases and as I said use cases is just a single class or a single function that is going to do our job so if there's a user sign up that's going to be one use case user login is going to be the second use case and we'll have to create separate classes for each one of them so what I'm going to do is create a new file here and call this user signore up do dot then I'm going to create a class user sign up and you see use cases should have a particular structure to them right I don't want use case to be anything the engineer wants to type we want some conform set of bounds to be present like it should return return something of the type of future either or it should take in some form of parameter etc etc so again for this use cases part I'll have to create my interface of use case now where should I create this interface for use case I can do it in this use cases tab but the problem is it will be accessible in the blog feature as well and I do not want to duplicate my code every single time so instead of creat creating a use case interface over here I can go ahead and create a use case interface in the core folder so I'm going to create a folder here called use case and in that I'm going to create use case do. File and in that I'm obviously going to have an abstract interface so let's create that and I'm going to call this use case now this use case is going to have two things present over here we'll get to that in a bit but for now I'm just going to leave it with angular brackets then inside of this interface I'm going to have a method just one function every use case is going to have just one function and I think I misspelled use case over here that's it and the reason it is going to have one function is because use cases are supposed to do just one task expose a high level functionality of whatever process you're doing for example sign up just expose the sign up method out so here I'm going to have future either and then I'm going to pass in Failure but here's the thing this use case should be accessible anywhere so if it's a failure obviously everything is going to return a failure but the success Can Depend for example in the blog feature we are again going to use this use case interface and in blog we're not going to return a string we're not going to return a user model or a user entity we are going to return a Blog entity so I cannot hardcode what's going to be the success value so what I can do is take it from the generic over here so here I can ask for a type or you if you want you can call this success type and then pass the success type over here so whenever the user is implementing this use case class they need to pass in their success type then I'm going to create this call function this call function is a unique function when it is inside of classes we'll understand that in a bit but for now you can just think of call as a normal function the next thing we want over here is parameter every function every use case is going to have a different set of parameters right user signup has three parameters name email password login only has email and password so we cannot set a fixed number of parameters here what we can do is ask for the parameter from the use case again and then pass in parameters like this parms params and there we go this is our interface for use case now I can go to the user signup class and Implement use case like this and you see we missing concrete implementations here but before doing that I'm going to pass in my generic otherwise use case is going to think that by default we have passed in Dynamic to prove it to you I can just create one missing override and you see it automatically puts in Dynamic and the params is also Dynamic but we do not want that so here I'm going to pass in the success type the success type as of right now is a string and the parameter what is that it is name email and password but we cannot take all of those three things from the generic over here what can we do then one thing I can do is create a class user sign up parameters and then take all of this from a class so we have user signup parameters over here and in this class we going to have final string email final string password and final string name then we can create a Constructor for this and if you're wondering how am I getting these options it's because of an extension in Visual Studio code that I'm using which is data class generator once you use this you'll get a set of options over here to generate your own Constructor so I'm just going to generate my Constructor and there we go I've also passed in my user signup parameters so that I can quickly access email password and name I hope you understood the purpose of this class we had to take in three arguments and we cannot pass three arguments like this in the grix it only accepts one so what I've done is created a class so that all these three can be taken now inside of user signup I'm going to create one missing override remove this and automatically import FP do do also when you use dot data class generator it automatically adds this we do not want it so you can remove it awesome so we have a call method over here this is a future so let's put an async and what I want to do is call the sign up with email password function that was written in the repository so you see repository has a bunch of methods in our case it only has two methods but as your functionality in the app increases there will be more functions we have user signup and user email now from that repository I'm just going to create one use case so that only one use case is thrown out to the block and all the unnecessary stuff is still kept in repositories so I'll have to take repository from The Constructor again we do not want the use case to have a dependency on the repository so again I'm going to have final Au repository and make sure to not use Au repository implementation we do not want to depend on the data layer we do not want any UT of data layer in our use case we also want to depend on the interface not the actual implementation so that's why we just going to have Au repository like this and then we're going to have our user sign up this do Au repository perfect now I can just take this Au repository and call the sign up with email and password function then we need to pass in the name email and password which I can do like this parms dotame followed by parms do email followed by params do password now this function is of the type future so what I can do is await it and then we'll have either failure string and actually if we think about it even this is of the type either failure string so what I can do is directly return this part so I'll directly do return await Au repository. signup with email password and the function will be executed I would recommend you to not do return Au repository. signup with email password even though it fulfills the condition since we have added async over here this function is of the type future and then we are returning either failure string doing this means you've called the function but the future may or may not be resolved so I always recommend you to do return await Au repository. sign up with email password don't forget this await because in some cases it might not work awesome our use case is now ready the final thing we have to do is set up the block that's our last layer before connecting the block to the widgets now to install block what we can do is go to Pub dodev and type in flutter unor block that's the package we looking for there's also the block package but flutter block provides widgets that are flutter based and can ease our development process so I'm just going to copy this and press command shfp add dependency and pass in flutter block after block is installed I would also recommend you to go to the vs code extensions Tab and search for the block extension by Felix off the creator of block this blog extension gives us multiple shortcuts that will ease our process while creating blocks so let's go to our Explorer and see what the block extension offers us so in the presentation layer what I'm going to do is right click and you see I have the option to create a new block if you don't see this option what you can do is command shift p type in new block and you'll see block new block if you want you can create a new Cubit that's not a big difference I'm going to be using block so that everyone can follow along nicely so after clicking on this it asks me for the block name I'm going to pass in the block name as Au and then hit enter and as you can see successfully generated O Block I can close this go to the block part and we see O Block O event and Au state do do files created I'm not going to go into much detail in this because I've already created a separate tutorial for Block if you want you can check it out so let's get into the O block and do some changes first of all I want to remove these two things we're not depending on block package we're using the flutter block package so let me import that there we go then I want to go in the Au event. file the seal class is immutable so I'm going to import the material. do package as well and that will fix our issue because that's where the at theate IMM newable comes from now in the O State we have a sealed class o State and a o initial class created I need to create two or three more classes the first class that I want to create is au loading because we want to display a loading indicator just in case we are loading so I'm going to extend that to all state I'm also going to minimize this after that I'm going to have final class Au success and that's going to EXT send the O State again and make sure to not do a typo and the final thing we want is an O failure class so let's extend that to the O State as well now I want to go in the Au event. file and here I want to create my first event my first event is the user sign up right and the naming convention in events is that we first put Au the name of the block followed by the event so it is sign up so Au sign up and that's going to be extending Au event now we can go to the Au blog. file and remove this on Au event what I'm going to do is catch the OD signup event so whenever the OD signup event is received we're going to run a function so that the signup process begins so we are going to have on which is a function over here and over here we'll have to pass a generic which is au sign up that's the event we are trying to catch so whenever we have an au signup request we have to run this function now what should we run in this function we only have to run a use case right if we go back to our diagram we have our block present over here the block directly depends on use case that means we need to call use case in the block so let's take it from The Constructor again we have final user sign up and this should be a private variable it shouldn't be a public variable because if you keep this as a public variable anyone can create instance of O block and call the user sign up variable we do not want to expose that outside so we're going to create this as a private variable then we can require this from the Au block so we have required user sign up and as you can see I've done required user sign up user sign up that means I've created a new variable that is being required from The Constructor and then I'm going to set this private variable equal to the user signup I've created in the Constructor this is called as an initializer list so just to summarize I've created a private variable over here so that it's not accessible outside then inside of the Constructor I've used require user sign up user signup and then set the private variable equal to the user sign up Valu that we get from The Constructor and don't worry this user signup variable is not accessible outside so this is a neat way to initialize private variables another thing you could do is without using the named argument you can just do this dot user sign up and that would be fine too but since we going to have multiple use cases inside of this I prefer using named arguments and when we do named arguments we cannot do this doore user sign up that's just not allowed because if you think about it the property would then be called underscore user signup and that's pretty weird so this way the property is now called user signup and is stored in the user signup variable which we are then assigning to a private variable I hope this makes sense now whenever we receive the OD signup event what we want to do is call this user signup use case so I can just do user signup and then use the dot call method on it right but there's another way to do this as I said this call is a special function it has a special meaning in dot whenever you have a call function that means you can call your class like this user sign up just like this and then this requires you to pass in user signup parameters so I can pass that in as well user sign up parameters like this now you need to pass an email password and name but we don't have access to that to get access what I can do is whenever we pass an OD signup event we can attach the email password and name because email password and name is going to come from the widgets right it's going to come from some form of UI so when we attach the Au signup event we can ask for the name email and password from the user so we have final string email final string password and final string name then you can require this from The Constructor put a comma over here so that the document is formatted now you can go in the O block and now if you see this event which is of the type Au signup will have things like event do email because all signup now has fields of email password and name right so I can just do event do password as well and finally event. name that's nice but when we call this method what do you think this use case returns it is going to return future either failure or success so we need to avade this and to avade it we'll have to make this function asynchronous this is a function right we'll have to make this asynchronous and then use await and then set it to a variable called response and finally we're going to resolve this response because it can either be a failure or a string and I said block is the place that that's going to decide if we want to display an error message or we want a success output to be shown on the screen so the controlling part happens over here so with this I can just do response do fold with this I can resolve the failure and the success independently that means whenever I have a failure I can use this L variable which is of the type failure failure class or this R which is of the type string so now whenever there's a failure what do I want to do I want to emit out a state that says that hey there was a failure over here so I can just use this emit function so I'll emit Au failure but you see Au failure doesn't take in any string so we cannot pass the failure class to it or the failure message to it so I'll have to go in AU State Au failure and take final string message and then I'm going to create cre a Constructor for this constant o failure this do message also this cannot be a constant so let's remove it because the O State sealed class is not constant if you want to optimize you can obviously do that by doing constant o State like this and then doing constant o failure like this now it works then coming back to O Block I can pass in L do message so our o failure now has the message attached to it next we have to resolve the success so what happens if there's a success then again we're going to use this emit function and emit all success State now in this OD success state that we have it has to take in some string right because success is going to have a string so I can just have final string uid that is the user ID and then create a constant Constructor of OD success this do uid perfect now I can just return this OD success doing R that's it because R is a string if you want to name this properly you can do it uid and then pass in the uid if you want to name this let's say failure you can do it by doing failure. message later on when we have more responses to resolve like this I'm just going to keep it as R and L awesome so our entire block is now created now I just have to set up this O Block so that our entire app recognizes this and then connect it to the user signup screen so as of right now our app doesn't even know that an O Block was created it's not configured anywhere right so in our main do do file we need to go ahead and wrap my app widget with a block provider block provider will help us register the block and since there are going to be multiple blocks that are going to be created so I can wrap this my app with a multi-block provider so I can do control shift R and then I'll get access to all of these things and you see at the end I also have block provider repository block provider block consumer Etc that's given by the block extension but none of them serves my purpose so what I'm going to do is wrap it with the column by a column we've used a column because I want to wrap it with multiblock provider and make sure to import the flutter block package now multiblock provider has providers with it I can also take this my app and remove it out it also has a named parameter of child so I can pass in the child as my app and then in the provider I can pass in my own block provider then in the create we need to pass in something like this create then the argument that's given out over here a build context that's not useful for us so I've put underscore and then we're going to return an au block because that's the block we want to register right now I'm also going to minimize this tab because there's a lot of explanation here you see OD block requires me to pass in user signup so I can pass in user sign up like this now user signup requires me to pass an au repository so to pass an au repository I'll have to pass an au repository implementation I cannot pass in the Au repository abstract class right if I pass in abstract class it cannot be instantiated so I'll have to pass Au repository implementation now Au repository implementation requires me to pass in a remote data source so I'll pass in AU remote data source implementation again we cannot pass in AU remote data source because that's an interface an abstract class so have to pass implementation and then finally this requires me to pass in super base which I have over here so I can just pass in superbase dot client and finally everything will be resolved you see just creating one blog provider had so much stuff in it and I had to import so many things I had to import stuff from the data layer the domain layer and the block layer and that's the last thing I want in main do. file so we'll be fixing this using dependency injection but since we've already typed all of this out let's go ahead and connect our O Block to the user signup screen so I'm going to close all the save files open the Explorer and go to the pages signup page now I'm going to scroll down and find my gradient button you see my gradient button is present over here now whenever this button is clicked I want the signup process to run but it doesn't expose any ontap function to me and this all gradient button is also being used in the login page so I cannot hardcode inside of this function that onpress should be this particular thing so what I can do is ask for the ontap from The Constructor so I can just do final void call back on press or on tap whatever you want to call this and then you'll have require this onpressed then I'm going to take this onpress and put it down in the onpress of the elevated button save it I'll come back to the signup page and I have onpressed over here there we go I'm also going to remove the const then I'm going to open the file explorer go to the login page close the Explorer find the error and your add onpressed again I'm also going to remove the const from all gradient button because functions are not constants now coming going back to our signup page here on the in the onpress first of all I want to validate the form you see I have my form key with me and we've already seen how to validate the form so I can just do if form key do current state current context you can do either of them dot validate so if the validate turns out to be true that means everything's all right then I want to call the OD sign up event on my Au block to do that I can just do context dot read and this read function which is an extension created on build context is given by the flutter block package also remove this widgets dot dot because we don't need it here we need to specify the type of block so mine is O Block and then you can call the dot add method on it and add the event the event I'm trying to add is o sign up then we need to pass an email password and name what is the email going to be email controller. text. trim if you want then password controller. text. trim and finally name controller. text. trim and this way I've added an event of au signup to my Au block I've added this event so that means O Block is going to get triggered then this function is going to run that hey on OD signup event okay so it's going to call the user sign up use case so the user sign up use case is going to run then we're going to call the Au repository and when we injected the dependency in user signup we passed an au repository implementation we didn't pass an au repository so that means Au repository implementation is going to be called and from Au repository implementation the remote data source implementation is is going to be called so that's the entire flow of the app I hope you understood that we are again going to dive deep into it after the entire authentication process is completed but over here I just want to take a moment and again reflect that what this Au repository interface is doing for us you see when we go to the main do. file this user sign up requires Au repository so we are successfully passing an au repository implementation and the same thing goes for the Au remote data source your we passing an au remote data source implementation if we are depended on the Au remote data source implementation over here instead of auth remote data source interface it would mean I could only pass this and it would seem fine at the moment but what if I decide to move from superbase to Firebase that means I'll have to rewrite this entire code and instead of rewriting it in auth remote data source implementation I can just go ahead and create a new class all super based data source implement ation and that is going to implement the Au remote data source so that I have all the methods that can be called in our app I'll be following a contract that would mean that I have strict conditions that hey you need to make this happen you need to follow this so it's highly unlikely that I would miss out on some function or method and this way the transition from superbase to Firebase would become much easy so I hope this makes sense now I'm going to close all the save files I've done everything so I'm going to restart my app and test the app I'll go in the sign up I'll pass in my name ran email let's call it ran ranavat gmail.com and pass in the password test1 234 then I'm going to click on sign up nothing shows up on the screen because you have not configured anything over there but if I go in super base you see ran ranavat gmail.com is being displayed with the provider of email and it was created just now and you see last sign in it's saying waiting for verification so an automated email is sent on my account and once I verify this this will change now we have our email showing up over here we have our user ID but what about the name that I passed in to view that you can just do view user info and you'll see everything instance id id AUD role email and if you scroll down you'll see raw user metadata in this raw user metadata we have a map with name and the value Ran So that means everything is being saved everything looks good now since we've completed this authentication process what I can do is work on the dependency injection in the main do do file so instead of having this mess over here I can refactor this code and make it look elegant so let's get into dependency injection with get it so now you might be wondering what even is dependency injection dependency injection is a designed pattern used to achieve inversion of control inversion of control means that the dependencies of a component and that component can be a class or a module so the dependencies of those components are provided externally rather than created internally take an example of this or repository implementation class you see we have Au remote data source and we're not creating this internally we taking it from outside we're taking it externally so from the outside we creating an instance of this author remote data source implementation and then passing it in this is inversion of control and we want to inject dependencies into it so that's what dependency injection is now get it makes our life pretty easy with that how think about it right now we have just one use case user sign up in a bit we also going to have another use case and that's going to be user login so we'll have to pass in something very similar to this the user login is going to be called user login but it's going to take in the same things right Au repository implementation or remote data source implementation followed by super base. client so we'll have to repeat all of these things and it's going to get really messy really quickly to avoid this get it becomes a very Cru crucial part in your applications with get it you need to register your dependencies and then you can just use the service locator to pass the dependencies that's it that's how easy it is so let's quickly install get it in our application you can find get it on the pub. dev website I'm just going to copy this and use the do add dependency to add it to my application after that is done we need to register our dependencies and to do that we we can do it in the main function but it can get really messy because there are a lot of dependencies we need to register Au block is a dependency user signup is a dependency Au repository implementation is au remote data source implementation is even super base is so registering so many things can be very annoying to see in the main function so what I'm going to do is open the file explorer and in the same level as the score and features I'm going to create a new file called in Itor dependencies do do here I'm going to create a function that is of the type future void and call it in Itor dependencies create an asynchronous function and that's pretty much it also let's fix the naming the function name should be like this in it dependencies now you might be wondering why is this future void why not just void the reason it is of the type future is because I want to take this super base initialization part and put it inside of inet dependencies function now I can quickly resolve these Errors By importing them and then call the init dependencies function in the main function so all the dependencies initialization is going to happen in this function since super base initialization is done I can get to registering the dependencies with get it so to register dependencies first of all we need to create an instance of get it and I'm going to do this globally so what I'm going to do is final let's call this service locator because get it is a service locator and I think the name service locator says it all get it helps us locate some services and the service locator variable should be equal to get it do instance now I can take this service locator to register my dependencies now as I said there can be multiple dependencies in our application so a good thing would be to create separate functions for separate initialization of dependencies that means I can create a function to initialize all the auth related dependencies and then another function to initialize all blog related dependencies so what I'm going to do is create a function which is going to return nothing so Vo and let's call this init o and also let's make this a private variable private variables in Python means that they're private to this particular file so I can use init o inside of init dependencies that's it but this init o won't be accessible outside of this file so I'm calling init o in the beginning of the function of init dependencies and in this init o what I'm going to do is register some depend dependencies so the first dependency that I want to register is super base and that cannot be done inside of authentication right super base variable is created over here so let's initialize it over here itself so what I can do is service locator Dot and there are two things you can do over here I mean there are multiple things you can do but people usually use either of the two methods one is register Factory register Factory means that you want the service look Ator to create a new instance of the registered type every time it's requested this means that whenever you ask for an instance of a particular type a new instance of the object is created so register Factory is suitable when you have types that are not meant to be shared across the application and need to be created on demand another function that people usually use is register lazy Singleton you use register lazy Singleton when you want the service locator to maintain a single instance of the registered type throughout the lifetime of the application this means that every time you request an instance of a type you'll get the same instance as the word singl suggests there's only going to be a single instance of this dependency throughout the app and that's what I want with superbase right every single time I ask for superbase a new instance should not be given to me I'm fine with the same instance being given to me so I can just pass in superbase do client over here and this way I've registered a dependency of superbase client now in the innit O I can start initializing other dependencies for example now I need Au remote data source implementation so what I can do is service locator again dot now what should Au remote data source implementation B should it be register lazy Singleton or register Factory I think every single time I ask for auth remote data source implementation I want a new instance of the object to be created so I can just do service locator. register Factory and then return Au remote data source implementation and pass in the super based client now to pass in the super based client what I can do is simply service locator like this as if I'm calling a function and this way I've registered Au remote data source implementation what I've done here is registered a factor so that means whenever I ask for something of the type of au remote data source implementation it's going to return this particular instance a brand new instance of auth remote data source implementation every single time now how get it works behind the scenes is that it sees this Au remote data source implementation all right and then it sees that hey this needs super super based client over here and the engineer has passed in service locator that means I need to pass in a registered object of the same type so it's going to go ahead and look for a registered dependency that has a type of super based client and here we have registered lazy Singleton which is of the type super based client so it's just going to take this and put it over here we don't even have to mention the type it will automatically get to know however if you want to mention your own type you can do it over here so after the service locator you can pass in grix and then type super base client and it will pass in the correct type just to be sure you can do this but there's absolutely no need get it a smart to figure it out on its own so this way I've registered a dependency for Au remote data source implementation the next thing I want to do is au repository implementation so let's quickly do it I'm going to do service locator Dot and again I'm going to do register Factory for all of the classes that I created auth repository implementation and auth remote data source implementation and even user sign up every single time the user comes over here I want a brand new instance to be created so I can pass an auth repository implementation and it requires remote data source so again I can just pass in service locator like this and it it will find the registered remote data source on by itself but here's the problem we have registered Au remote data source implementation not Au remote data source and this Au repository implementation requires a type of au remote data source now that can be an issue because get it doesn't know that Au remote data source implementation implements Au remote data source so we need to manually fix this how can we do that well over here when we trying to register a factory I can pass in a generic type that hey what am I returning what is the type of the object that I'm returning and I'm returning Au remote data source so I can just pass it over here if you try to pass in some other data type let's say int it's going to give you an error it automatically recognizes if it's valid or not so make sure to pass an auth remote data source so that no other error occurs in the registering process awesome now that we've done Au repository as well let's do user sign up so we can do service locator do register Factory and then we can pass in user signup and then we again need to pass an au repository so I'll do service locator and now we have the same problem over here this accepts a type of au repository and here we are initializing the type of au repository implementation so I'll have to manually say over here that hey this is of the type Au repository after this is done the final thing is au block I can register this as well so what I'm going to do is service locator Dot and this time instead of using register Factory I'm actually going to do register lazy Singleton why that's because I only want one state of my O Block to be present I don't want multiple states to be present because that would confuse my app if a new instance of O Block is created every single time that means my state would be lost let's say my app is in a loading State and suddenly a new instance of O Block is requested that means the loading process will disappear and again my app will be initialized to Au initial which is the initial state of O Block right if you see over here o initial is the initial State and that's not what I want I only want one state to be person assisted that's why we're using register lazy Singleton so here I can directly pass an au block and then for the user sign up I'm going to pass in my service locator so this way we have registered all the dependencies and we know how to use these registered dependencies just calling service locator like this does the job but remember one thing if you've not registered a dependency and then you're trying to access that using service location it's going to cause an issue what I mean is let's say you've not registered Au remote data source okay and then you're trying to use service locator for the Au remote data source it's going to give you an error because it doesn't know that a dependency like that exists so make sure to register your dependencies first only then can you use them and I hope the concept of register Factory and register lazy Singleton also makes sense there are multiple methods that you can use like register Factory async register Factory param register Factory param async but broadly these are the two types okay now that we've understood this I can close this and make sure await in it dependencies is called and after that in the block provider I'm going to remove the entire o block part and instead I'm just going to have service locator like this but now how will the service locator know what type of block to pass in it doesn't even know if it has to pass in a block or not so definitely we'll have to pass in our own type over here and I'm going to pass an O block and since we've already registered O block it shouldn't be a problem to us so I'm going to remove all of these unused imports from here then I'm going to restart my entire app go to the sign up process let's say this time my name is nam the email is Naman ranavat gmail.com and let's say my password is test1 123 then I'm going to click on sign up I'll go to the super base dashboard and I see namat gmail.com showing up over here and just to confirm I can click on these three dots view user info scroll down and I'll see raw user metadata with the name of num so everything seems to be working fine that means our entire dependency injection task was done successfully the the next thing I want to work on is storing the user data in the database so as of right now we are storing our data in the authentication tab so whenever a new user is created we are storing the details over here and that's fine but I want to go one step further and also save this data in our database superbase offers a built-in database which uses post graphs so it's an SQL database that we can use and generally whenever you have a users table it always always helps later on in your application so we going to create a new database table over here if you're from the Firebase world you might know collections you can think of tables as some form of collections so we want to build a table which contains all the users in our application now there are two approaches I can take the first approach is manually putting the user in authentication Tab and manually putting the user in the database table the second approach is by creating an automatic trigger that means whenever a new user is added in the authentication part we automatically add it to our database and that's the approach we going to go with because super base makes this really easy now to set up this trigger we first need to create a database table and to create a database table you can use the GUI that superbase has it's very easy to use where you need to pass in the name of the table so it can be profiles user whatever then the description which is optional then if you want to enable role level security this basically means writing your own security rules so that you define who can use a particular Row in your table so you can set up a rule so that only the user themselves can change their data in the table no other user can change another one's data so for example if we have two users user a and user B you can set up a ro level security such that user a cannot change the data of user B that's what Ro level security is going to allow you to do and then you have columns so what fields are present in this table a user is going to have an ID they're going to have a created at table then there's also going to be a name property you can Define all of that then if you have a foreign key relationship but we'll talk about foreign Keys later when we trying to create our own blog table but anyways I'm not going to use this GUI so I'm going to discard this what I'm going to do is go to this tab SQL editor and here I'm going to type in my own SQL query and run it instead of writing the query on our own from scratch what I'm going to do is go to the Super based documentation where they've written a Blog on building a user management app with flutter here they've listed all the steps to build a user management app you can go over them if you want we've covered many of these things like creating a project entering project details but what we need to do is set up the database schema by database schema I mean how our entire users table is going to look like and instead of following all the steps that are written over here what I'm going to do is change to SQL and then copy this entire thing that I see there's a copy button over here I'll copy all of this text and put it inside of this query Builder you see a lot of lines come in now we going to go over every single line and understand what they do so first line is creating a table and please note all of this is SQL okay that's how you create a table in SQL as well so what we are doing is creating a table with the name profiles and in that we are defining the fields or Columns of our table the First Column is ID which is of the type uu ID that means we're creating a unique user ID and this is referencing au. users references au. users means that the ID is coming from whatever the au. users has so if I just go to the authentication tab the ID that's mentioned over here is going to be the ID of the user in this table and that's exactly what we want in the profiles table the ID of the user should be the same thing as what's mentioned over here because it's the same user right so this is how you do it and then we saying that this should not be a null key and that it is a primary key primary key in SQL means that this is a unique column in this table so that means any other user cannot have the same value if there is the same value then it's just going to override the data and remember this a table can only have one primary key in users table ID is the primary key then we have the field of updated at with the data type of timestamp then there's username of the type text and the username always has to be unique then we have full name which is of the type text avatar URL which is of the type text and website which is of the type text now don't confuse unique with primary key there can only be one primary key in our entire table however there can be multiple fields that are unique so even full name can be unique even Avatar URL can be unique but only one one column in our table is going to be a primary key so all of these are our columns in the table then we have a constraint where we checking if the username length is greater than equal to three if it's less than three that means it's going to give us an error so that's a good constraint that super base has put in then we are setting up the role level security for this table so you see we have put an alter table profiles enable row level security so this way we are enabling Ro level security and then we are creating a policy for our Ro level security so this policy says that public profiles are viewable by everyone so on the table of profiles everyone can view the public profiles then we creating another policy on the profiles table which says users can insert their own profile and here we are just checking if the o. uid is equal to the ID that means it's the user themselves that are trying to insert some form of data then we have another policy that says users can update own profile and here it's basically the same thing like this but instead of insert we have update now if we scroll down this is where our trigger is created in the beginning I said that whenever a new user is created in the authentication tab I automatically want a user to be created in the profiles table this is the trigger that's created so here we've created a function which is public called handle new user and then we have set up a trigger and here we have specified that in the profiles table we need to insert ID full name and Avatar URL and where are those values going to come from we can find that over here so we have specified values new. ID your new stands for this o. users okay so we are able to get the ID of the user then we want to access is the full name and we saw that our additional data that we are storing is being stored in this raw user metadata so what it's doing is going in new raw user metadata and accessing the full name that's present and then it's doing the same thing to get the Avatar URL new raw user metadata Avatar URL and then we are returning new from here so this way we' have created a function now finally we need to attach the trigger whenever the user is created in the Au section so here we have said that create trigger on Au user created after a new user is inserted in the au. users section we need to execute this handle new user function so you see this entire part does this job this trigger automatically creates a profile entry when a new user signs up via superbase off superbase also offer storage so here we setting up the Storage storage is used to store files that are one 1 MB or 2 MB for example your image your audio file or any other form of file that will be stored in storage they cannot be stored in this database so here we are seeing that in the storage. buckets we have to store an avatar and then we've created policies for each one of them as well so I hope all of this code is understandable to you now let's go ahead and edit this code so that it suits our own apps functionalities so the first thing I'm going to do is remove the storage part because our users aren't allowed to change their profile picture or in fact our users don't even have a profile picture now if you want you can add the profile picture in your application but in this one we not going to have one I'm going to remove all of this setup storage code after that I can go at the top and update the profiles table over here so our user is going to have an ID which should reference all do user and should not be null and it should be the primary key so everything's fine with this then we have updated at so this looks fine as well the next thing I want is to remove username the username is not present in our application only a name is present so I'm going to convert this full name to a name and it should be of the type text and two users can have the same name that's not a problem with me I'm also going to remove the Avatar URL I'm also going to remove the website text then here we have a constraint where we check username length is greater than equal to three so I'm going to change it to the name length so I'm going to remove the user from here name length here I'm going to check if the character length of the name is greater than equal to three then I'm going to let this roow level security be as it is I don't have an issue with that I'm going to scroll down and here in the handle new user function I'm inserting values right so the new do ID is fine my user ID is this particular thing new. ID that's all right with me but then I'm only providing a name of the user in the Raw user metadata so I'm going to update that so instead of passing in a full name here I'm going to pass in a name let's remove Avatar URL that's not needed and then let's match all of these fields so ID has new. ID name has new. raw user metadata full name so instead of full name it's is going to be name and at the end we have Avatar URL part which we going to remove so that's how my table is going to look like and that's all the changes I needed to make so what I'm going to do is run the query to run it I can just click on this button and here you see success no rows return and you can see super base also saves my queries over here now if I want to see if a table was created or not I can go in the datab datase and here you see in my database tables I have a new table profiles right now there are no users inside of it that's because we just created a database table now whenever I insert a new user in this authentication tab this database table should automatically get filled so what I'm going to do is delete both of these users and after that is done I'm going to restart my entire app and then go to the sign up page going to create a new user so I'm going to call this ran the email is going to be ranr the gmail.com password is going to be test123 sign up and let's see if a new user is created here a new user is uploaded in the authentication tab that's good if you don't see the user just click on this reload and see if the user pops up over here then you can go to the database and in the profiles table as you can see I have one draw so new user has been added now to see if if it's the correct user or not what I'm going to do is go to the table editor go to this profiles Tab and here I have the ID you see it is labeled a bit differently from the two Fields but yep the ID is the same as the ID that was present in the authentication tab to verify I can just copy this go to the table editor go to the profile section and here you can see it's the same thing the updated ad is null because we have not provided any value for updated ad and then we have the name ran everything looks good as of now now you might be wondering what are these two signs the first sign over here is primary key and as I said primary key is the unique identifier for the stable so ID is the unique identifier and then we have a foreign key relation what is a foreign key a foreign key is a column in a database that is linked to another column in a different table to explain explain this better I'm going to go to the database part here we have schema visualizer I'm going to click on that and here you see I have my profiles table created it has the fields of ID updated at and name this tells that it's a primary key and then we have a foreign key relationship this means that ID is connected to a primary key of another table so we are connecting a profiles table with the o. users table using ID now later on when we add our own block table that is going to have a field that is connected to this ID of the profiles table and that's why SQL becomes so powerful you can connect two database using one field this line that you see that represents that both of these tables are connected so basically a foreign key is a column in one table that matches a primary key in another table the primary key of od. users is ID so it's matching that you'll understand the benefit of a foreign key later on when we get to the blog section but for now you can just think of it as something that connects the two tables together so I hope that's clear and with that we are able to store our data in the superbase database as well the next thing I want to do is create a user entity so that instead of returning a string from our data sources and a repository we are returning a user model this way we will also have access ACC to our user model throughout our entire program so let's get to that to create an entity what I'm going to do is open this file explorer part and from this file explorer part I'm going to go to the features o in the domain layer I'm going to create a new folder called entities and in this entity I'm going to create a file called user. do now if you want you can call this profile do dot just to match it with our super based table but I think think I'm fine with user now here I'm going to create a class of user and then I'm going to specify the structure of my user what are the fields that are present in my user it's going to be final string email final string name and final string ID actually ID is the first field so let me just put it so that there's more structure not that it makes any difference after that I'll generate a Constructor for this so I'll just create so my entity is now created if I refer my diagram the domain has entity that's done now I want to create a model this model is going to help me shape my data from remote data sources into a structure of user so let me create a user model quickly so I'm going to go to the Explorer and in the data part I'm going to create a new folder called models and this is going to be called user model. do then I'm going to minimize this and here I'm going to call this class user model and this is going to extend the user entity that we created so the user model extends the user but not the user that's coming from superbase flutter remember that it shouldn't be coming from superbase flutter let me remove that what we want to do is import the user class that's coming from the domain layer the reason we are extending from the user is because user model has the same structure as our user if we refer to our diagram we want to convert the data coming from the remote data source into a structure and we cannot use an entity that's present over here data layer should have its own models it cannot be used outside of the data layer so what I'm doing is creating a model that extends this entity so that we follow the L in solid principles which is Lisk of substitution Lisk of substitution basically means that I should be able to replace model with entity and entity with model when a repository is being called in this use case I can replace the user model with an entity you'll see that later in the code but I just wanted to point it out right now so coming back to our code here let's fix the error we are extending the user so obviously we have some fields that we need to pass in to this user so if I just go over here click on this bulb icon and create Constructor to call Super it will automatically do that for me what's Happening Here is we are asking for the ID of the user from The Constructor and then passing it to our super class using super. ID it's basically doing the same thing as requiring string. ID and then calling super like this something you might have seen but this is just a shorter way of doing the same thing now what I can do is go to the Explorer go to the data sources and in this Au remote data source I can update my Fields now instead of returning a string everywhere what I want to return is the user model so I'll scroll to the top in my interface I'm going to return a future user model and make sure to import the model from the data layer even over here we going to have a user model don't pass in a user over here not a user that comes from Super based flutter not a user that comes from the domain layer it should return a user model later on when we go down our path somewhere over here we're going to replace our user model with the user that we created in the domain layer so as of right now it should just return a user model now I'm going to solve these errors by changing the return type over here as well and now it should give me an error over here the error should be there because we are returning a string and we want to return a user model instead now how do I return a user model based on this user that I have the answer is pretty simple if I go back the response. user has a function called tojson and this 2 Json gives me a map of string comma Dynamic so what I can do is take a map and convert it into a user model but where should the code of this conversion be written it should be written in this user model the reason it should be written inside of this is because the function would then become reusable so for example when we write our login functionality we'll have a similar problem we'll have to convert response. user to a user model so instead of manually writing our logic over here what I'll do is write it in this class this way I'll be able to reuse my logic and my code would become cleaner and neater so what I want to do is create a factory user model do fromjson function and this J from Jon function is going to take a map of string comma Dynamic let's call this map and also fix the keyword Dynamic and then based on this map I'm going to convert it to a user model and return it from this function so I'm going to return user model and then pass in the ID the ID is map ID just like this the email is map email the name is map name as simple as it gets so with this we are done now if you want to handle some form of H case we can do that for example this map of ID can be null right so we can put two question mark followed by an empty string so just in case this is null we're going to put in empty string otherwise the value of map ID is fine we can do the same thing for map email and map name so fromjson function is now ready I can go to the auth remote data source and instead of returning this map I'm going to wrap it with the function user model. fromjson then I'm going to take all of this and put it inside of the map there we go now there's no error in our function and hopefully it works now you might be asking why have we not written this fromjson function inside of this user entity the reason we've not done this is because user entity is not fetching any data from anywhere this user entity only exists so that we can access the ID email and name property only user model is related to the fetching task so only user model should have this function this way when we have to test we don't have to test the user class at all it doesn't have any logic related functionalities but we will have to test the user model class because something can go wrong in this fromjson function hopefully that makes sense now what I'm going to do is close all of the save files and we see in the repos repository layer we have an error let's go into that in the Au repository implementation we are getting a user model that we are returning right we need to change that and to change auth repository implementation first we'll have to go to The Domain layer and change the Au repository interface so here instead of returning a string I have to return a user now we not going to pass in a user model over here why because we are in the domain layer think about it if we are in the domain layer we cannot access stuff that comes from the data layer that's the entire reason why Au repository interface even exists in the first place so what I can do is instead of returning a string I'm going to return a user that comes from the domain layer don't import the user coming from super base so I'm going to quickly import that and I'm going to replace it in the login with email password too then I'm going to save this file and then move to Au repository implementation. file here instead of returning a string again I'm going to return a user so let me import that again import the correct version also import that and save the file and now if you see in the sign up with email and password function a user model is returned and it satisfies the condition also I think the naming is a bit misleading so let's convert this to you user and return right user so with this we get the user model and we returning the user model and it satisfies the condition because user model extends user user model is a child of the parent class user so the list cost substitution principle says that I can replace user with user model and it shouldn't give me an error and that's what's happening now if I go in the domain layer use cases user sign up there's another error and the error exists because here also we have specified that we returning a string we shouldn't be returning a string we should be returning a user now onwards we'll only be using the user entity the user model is only there for the data layer it is not there for the domain or the presentation it's only there so that we can fetch the data and return it now I'll take the user and pass it in over here as simple as it gets now I can again open the Explorer fix the error in the presentation layer so in the O Block we are returning all success uid but we're not actually getting the uid we getting the user so I can name this as user user go in the OD success class and here instead of asking for the uid of the user we're going to ask for the user that comes from the domain layer this will fix our error all over the place so for now I can assume that everything works well and start working on other aspects of the application for example whenever the user clicks on sign up I first want the user to see a loading indicator and if it's a failure I want the user to see an error message if it's a success they should move to the home screen so these are the things we need to set up now what I'm going to do is in the O block whenever we get the O sign up event I'm going to emit Au loading so that means we are in the loading State now after that if it's a failure it will get converted to Au failure if it's a success it's going to be Au success I'm also going to remove this print and save the file then I'm going to close this part going to go to the sign up page and here set up the error displaying part so I'm going to wrap this entire form with a widget known as block block consumer block consumer is a mix of block Builder and block listener block Builder builds the wiget based on the state of the block and block listener helps us navigate from one page to another or display a snag bar based on the state so block consumer combines both of them which I'm going to use so I'm going to pass an au block over here and then in the Builder I'm going to check if the state is off loading so if the state is offloading that means I want to display a loading indicator to display a loading indicator I can create a custom widget for it because this loading indicator is going to be used in the signup page the login page even the blog Pages because as we fetch data from super base I want the loading indicator to be shown so obviously that means it's going to go in the core folder because it's a shared resource across all the features so here I'm going to create a new folder called common and in that common I'm going to create a new folder called widgets and in that I'm going to create our loader let's call this loader do dot then here it's going to be a stateless widget which is called loader and then I'm going to return a center child of circular progress indicator that's it that's my loading indicator if you want to change this you can make this more stylist by using RVE animation or any other form of Animation mine is pretty simple then I'm going to take this loader and return a const loader so this way loader is going to become a reusable widget so whenever you want to change how the loading indicator in your app looks like you can just change it over here you have one centralized place of control for that so anyways if the state is offloading we return a loader otherwise we going to return on a form now in the listener I'm going to say that if state is au failure if the state is O failure what do I want to do I want to display a snag bar snack bar means that a little widget from bottom appears that shows the error message to us now that snag bar is also going to be a reusable function so I'm going to go to the core folder and create a new folder called utils in this utils I'm I'm going to create a new file called showcore snackbar do dot this is going to contain just one function void show snag bar with the parameters being build context and the content that we want to display then I'm going to do scaffold messenger do off context do dot hide current snack bar dot dot show snack snack bar then I'm going to pass in my snack bar where the content is going to be the text followed by the content that we take from the parameter so this is a way you show a snack bar now I've done hide current snack bar because if there are two snack bars that are in progress we want the previous snag bar to get hidden away when a new snag bar appears so it will hide the current snag bar to show the recent snag bar now I'm going to call the show snag bar function so I can just do show snack bar pass in the content as let's say state DOT and you see I get an autoc complete of message because I've put in the if condition that if state is off failure so it knows that this state variable is now off failure so if the state is off failure it should have a message property which we are displaying awesome now I can restart the entire app then in the sign up I can just say num email as Nar at the G gmail.com password as test12 34 sign up and we see the loading indicator showing up and we also see that we don't get any error message and the reason for that is numr the gmail.com has been added to our authentication Tab and if I go to my table editor profiles we should be seeing n name over here perfect now you saw that whenever we have a success part we're not doing anything what we want to do is move move from the signup page to the homepage because now we're logged in but that's a thing we will cover later on in our application for now the signup page seems to be completed the next thing we need to work on is the login feature and it's very very similar to the signup feature so let's complete it really quickly go to the author remote data source to complete my login with email password function so in this function the first thing I'm going to do is remove this throw part then convert this function to an asynchronous function and then I'm going to minimize the Explorer now everything in the login with email and password function is going to be very similar to sign up with email and password so I'm going to take all the TR catch block statement present inside of sign up with the email password copy it and paste it over here after that I'm going to change this line we signing up the user over here instead of signing up I want to sign in the user with password so I'll use that function now the data part does not need to be put in because login does not store all of that information and we do not want it to store we only have an email and a password that's good after that we're going to check if the user is null then we're going to through a server exception saying user is null otherwise we are going to return a user model from Json that's present over here and if there's any other error we're just going to throw a server exception again so our login function is now ready the next thing we need to do is go to the repository in the domain layer so I'll go over here and see the login with email password function is nicely written over here so everything looks good in this repository so I'll go to its implementation in the data layer and start working on that so I'll try to find sign in with the email password there we go and convert this into an asynchronous function again we're going to have a TR catch block so let me put that in and here we're going to catch a server exception we have seen that before and if there's a server exception we want to return left and then we're going to return a failure class saying e do message perfect now in the TR catch block what do I want to do I want to take this remote data source and call the sign in function so we're going to get our user which is equal to await remote data source Dot and then we're going to call the login with email password function then we're going to pass in our email password and then we're done now the user that we get we want to return it so we going to do return WR user and this way our Au repository implementation is done if you look at this function below sign up with email password you'll see both of these functions look pretty similar we call the function and then we are returning right if there's any exception we returning left so there's a scope of refactoring both of these functions and write much cleaner code what I mean is I have a scope of creating an extra function over here let's call this get user function the return type of this function is going to be future either failure or user and it's going to be an a as synchronous function inside of this asynchronous function we're going to copy paste all of this the entire TR catch block statement so I'm going to put that in now instead of calling this function what I'm going to do is take this function from the parameter that means I'm going to have a future user function taken from the parameter let's call this variable function so I'm taking in a function that returns future user and the variable name is fun function now I'm going to call this function and then whatever user I'm going to get I'm going to return that now I can take this function and instead of doing all of the TR catch block statement over here what I can do is remove them and instead say return get user and from here I'm going to return this thing so I'm going to take it paste it over here and there we go also this function is going to be asynchronous so let me put that in so what have I done over here I've basically created a rapper function around this function what this rapper function does is put all of the code inside of Tri catch block and if there's any exception it's going to return left but if there's no error then it's going to return a particular user the reason I've done this is because the code written over here and the code written over here are basically the same thing so that means I can remove the TR catch block from here as well and then say return get user and make sure it's a private variable okay I don't want this get user function to be accessible outside of this file so I'm going to take all of this and put it over here then this is also going to be asynchronous let me put a comma so that the formatting is right so with this get user becomes a reusable function so so what happens is this get user function takes another function which returns future user so we pass our login with the email password because both of them return future user model right and user model inherits from user class so we pass that in as soon as that's done get user function is going to get called and from here we try to run that function when we run that function if it is successful it's going to return the user to us where we return right but if there's any exception it's going to return left the same thing happens with sign up with email and password so with this if I have any changes to make I don't have to make any changes in this function what I need to do is go to this function and change all of my code for example if I want to see if there's any o exception that has occurred I can do that what I can do is check on AU exception and this on or exception is given by super base to me so I'll do on or exception catch e then I'm going to return left failure e do message simple enough now you see we are getting an error and that's because Au exception is coming from the super based library and super based Library exposes the user class and our own class that we created is also called as user so what we need to do is go up there and prefix our import so when we import superbase flutter I can tell thatt to import it as SB and whenever I call on o exception I can do on SB do o exception so whenever I use any super base related class over here I need to prefix it with SB do so you see the use of this function is that any changes I need to make make for any of the function I can do it over here I needed to catch o exception in both of these functions so instead of putting them over here I put it over here because as the file size increases we going to get more and more functions so I'll forget to put on off exception one place and then maybe my application crashes and I do not want that so this is a good practice to do so I hope that was clear and if it was let's move ahead so from Au repository implementation I'm going to go to the use case we already have a user sign up use case I'm going to create a new use case called user login. dot if you want you can also call this user signin dot then I'm going to create a class user login which is going to implement our interface use case now we need to pass in two types over here the first type is the success type so from here obviously I'm going to return the user that comes from the domain layer and the other thing that I want to return is the parameter the parameter in this has to be created down below I'm going to create a new class called user login params and that is only going to have two things final string email and final string password then I'm going to click on this bulb create Constructor for final Fields And format this after that I'm going to take this user login params and put it over here then I have a proper class created I can again come over here press command full stop and create one missing override so with this I have the call method with me now I can remove the unimplemented throw error put async over here and just return whatever the repository login method is now obviously for that I'll have to import repository so I can do final Au Repository Au repository then create a Constructor for this so I'll have constant user login this do Au repository then I can take this Au repository and call the login with email password function now to pass in the email I can do par. email and password can be parms do password also make sure to use return AIT AU repository. Lo in with email and password I've already explained this to you before now instead of importing either dot we can import the FP do do package cool now since our use case is ready let's go down in the O block and create a block for that so from The Constructor we are also going to import another use case which is going to be user login so let me make this a private variable then I'm going to requir this from The Constructor so I've required user login user login and in the initializer list I'm going to pass inore user login is equal to user login simple now I need to catch the Au login event and as you can see this seems very populated so to clean this mess up what I can do is take all the code written inside of the OD signup function and create a new function for it so I'm going to create a function void and it's going to be private and I'm going to call this on o sign up then I'm going to paste everything and from the parameter I'll give the type because both of them are Dynamic right now the event is going to be OD signup event and the emit is going to be emitter of OD state so there we go now I can take this on all sign up and paste it over here now I need to create a new event with this our code over here looks less messy all of our implementation is down below and up we have only called the function it's going to work as normal we've just created a new function instead of an anonymous function up there now I need to create a new event for o login so let me go there I'll click over here and then I go to the Au event. file here I'm going to create a new class called Au login which is going to extend the Au event class then here I'm going to have two Fields final string email final string password which I need to take from the user and then I'm going to click on this bulb create Constructor for final fields and save it then I can go to the O block and here listen for the Au login event so I'm going to have on Au login event I want to call a function that looks like this so I can just copy the entire function definition and paste it down here now instead of calling this all signup I'm going to call this on o login the event is going to be Au login and the emitter is going to be the same Au State now in this function the first thing I want to do is emit an au loading state after that I want to call the use case so I'm going to call underscore user login like this and then I need to pass in the parameters so I can call the class user login params then pass in the email to get the email I can do event. email password is event. password and obviously I also need to avade this and this is going to return either failure user so I can store all of this in a variable now to format this I need to resolve my errors up so I'll copy this function paste it over here and save it this way everything's now formatted after that I can resolve this either part so to do that I'll do res. fold if there's a failure what do we want to do I want to emit Au failure and then the message is going to be l. message and for the success part I want to emit o success and then pass in the user model which is just R so our entire Au block function is also completed the next thing I want to do is go to the Explorer and you see in our inet dependencies there's already an error there's an error because we need to add a new named parameter called user login now to get the user login we first have to register a user login event so let me do it right beside this user signup so I can do service locator. register Factory user login and then I can just pass in the service locator which is the auth repository and get it is automatically going to do that you see this is the benefit of using get it if we weren't using get it we would again have to pass in AU repository implementation and in AU repository implementation again we would have to pass in AU remote data source implementation and in all remote data source implementation again passing super based client but now everything's so easy as we only need to pass in service locator now we don't have to worry about registering any other thing because rest of the things are registered for example the repository and remote data sources registered and those are the two places where I edited my code so everything looks good now I can close all the save files and move to the login page here we have the sign in part what I need to do is call the login function over here so I can do context. read and then pass in AU block as the generic type and here I want to add the Au login event now in the Au login event we need to pass an email and password so the email is going to be email controller. text. trim and password is password controller. text. trim and before doing all of that remember we also have a form created so I need to validate that form key too so I'll have to do form key do current state do context do validate not context sorry current state. validate now I can put all of the code inside over here and save it so this is something we've already done in sign up page so I rush through the process I hope you've understood it now I'm going to restart the entire app and actually let's have faith in ourselves and go one step further let's also add a block consumer on the top and see if it works so above this form I'm going to wrap all my code with block consumer and then I'm going to pass an a block like this now in the Implement listener I'm going to do the same thing I did in the sign up page if there's a failure I want to display a snack bar so I'll just go to the sign up page to quickly copy paste some stuff so if state is off failure do the same thing now we need to import show snag bar so let me do that then I can go to the sign up page and again we going to check here if state is off loading then we want to return a loader so I can do that in the Builder again I'll have to import loader I'll do that save the code restart and let's see if it works so in the sign in I'm going to pass in numr gmail.com I think the password was test 1 2 3 4 click on sign in and we get an au exception email not confirmed status code 400 now in your application you might want to enforce that the user cannot sign in until they are verified but in my app they can sign in even if they are not verified so to fix that I'm going to go to the super base dashboard in the authentication tab I'm going to go to providers and you see there's a little drop down you can click on that and here you have a bunch of options to select minimum password length OTP expiration secure password change secure email change confirm email enable email provider what I want to do is disable confirm email that means users don't have to confirm their email address before signing in for the first time then I can click on Save and it's done so hopefully that's fixed now let's go to the sign up to create a new user ran ravat and the email I'm going to pass in and the password is going to be test 1 2 3 then I'm going to click on sign up and we don't see any error so hopefully that's been fixed and you as you can see we already get this that means the user is logged in now I'm going to restart my entire app so that I go to the signin page now here I'm going to pass in my email and also present a password then click on sign in and there's no error so I think the user is now logged in as you can see last sign in was 52 so that means the user is able to sign in the users that are created before the authentication policy change probably don't follow the same rule so they're still waiting for verification if you want you can delete these users so that there's consistency among your users now just to verify I'm also going to go to the database sorry table edor profiles and see that the user is present awesome so now that we done with the login and sign up features I want to take a moment and go through the clean architecture again so that we are on the same page I'm also going to take help of this diagram to explain the solid principles and the clean architecture relationship but first let me explain this to you again so if you think you're already familiar with the concept that's great I recommend you to go ahead with other sections but now I'm just going to revise clean architecture with the example from code over here so first we saw that in clean architecture there are three layers presentation domain and data so to follow that in our features folder we created one feature called o and it has three layers data domain and presentation in the presentation layer we created a Pages folder and in that page we created our two authentication Pages login and sign up we also created a widgets folder where we put in reusable widgets like o field and O gradient button so that is the widgets part then we needed the presentation logic holder that communicated directly with the widgets so we created a block layer that is O Block now O Block requires Au event and O state that we also created now this o blog directly communicates with the use cases and if you see that's what we imported from The Constructor user signup and user login use case now all of these use cases only provide us with a single feature so user signup only deals with the feature of signing up the user the user login use case only deals with logging in the user feature then when we go to a particular use case let's say I go to the user sign up use case we are directly contacting with the Au repository interface interace and you can see over here we're directly asking for the Au repository interface we're not asking for anything that's an implementation because just in case in the future we want to change our database we'll not be using or remote super base implementation we'll be using let's say or Firebase implementation so we can create a different class in that scenario so here we are asking for the interface so as you can see the repository that was created in the domain layer is being used in the use case now since we are in the domain layer we also have entities created and this entity is the user class this entity can be used throughout our application and this entity also serves as the base model the parent class for the model we create in the data layer and this user class doesn't have anything that's extraordinary it just has three Fields defined the properties of user class and a Constructor for that so this class should not be tested because there's no logic present inside of it so anyways coming back to our use case we saw that we're directly talking with the interface that is present in the domain layer however the actual implementation is present within the data layer and again just to repeat because this is the most important part the repository is also created in the data layer and that is the actual implementation it is created so that the domain layer does not depend on data layer because data is a lower level module and domain is a higher level module and higher level modules should not be concerned of what's going on in the lower level detail or lower level module so let's go to the data layer repository and here we see an actual implementation created of the Au repository we are directly communicating with the Au remote data source and again we're not depending on the actual implementation of author remote data source we're depending on the interface that we created in the data source file itself so if I go to data source we see over here we have an interface created that's the whole point of clean architecture you should not be depending on the actual implementation you should be depending on abstraction now in this data source you can see I'm depending on super base which is our external database or external API and it gives us raw data so we get our raw data over here in form of response. user. tojson so that is a raw data and we are converting it from raw data to a model using this function from Json and this function is defined inside of our user model class and this user model class is this model and it is extending the user class that was present in the domain layer it is extending ing The Entity because both of them represent the same thing the only reason we're not using user inside of data layer is because we don't want both the layers to be dependent on each other they should be independent of each other and then when we return user model from here we're basically calling this function in the repository so you see model points towards repository so I hope this entire clean architecture is understandable to we'll be using the same thing in the blog feature as well now just to demonstrate the relationship between solid principles and clean architecture we have this diagram you see we have a presentation layer where we have our block provider or any other state management tool we have our Pages the theme is not defined inside our presentation layer we have defined it inside of our core folder because we have defined core as a folder that contains resources that can be shared across multiple features then we also have components which is widgets then this presentation is calling stuff from the domain layer the use case and you can see use cases follow o and S of the solid principle the open or close principle and the single responsibility principle let me explain how they follow these principles so if I go to a particular use case let's say the user sign up use case what is user signup doing it is only dealing with the signup feature of the application so it only has one responsibility to do that's why it's following the single responsibility principle it is also following the open or closed principle because this class is open for extension but closed for modification so if I want to extend this class's feature I can do so but I cannot modify the already exist existing things inside of it and it makes sense why would I you saw that when I was creating the user login use case we had completed the user signup feature and we wanted to add the user login feature I wasn't bothered about this use case that was present I directly added my own use case of user login without bothering this class so this class follows the open or closed and single responsibility principle then in the domain layer we also have entity and you'll see that entity and models from the data layer are both linked together the model from the data layer extends the user from entity and that is the list of substitution principle the L ins solid principle this means that I can use user model instead of user and that's exactly what we did if I go to the repository or repository you see I've mentioned user over here okay my success return type is a user but if I go to the repository implementation and see we are returning a user model and even then it satisfies this return data type bounds because user model is a child of user class so that's where we have used List cost substitution if we go to our repository class again here we are also following interface segregation because we have our auth repository implementation that implements this inter interace and this interface only deals with the authentication task the login and the signup feature and if I have any other feature I'll be creating a separate interface for it and between the domain and the data layer We are following the dependency inversion rule so if I go to a particular use case again let's say user sign up I have Au repository over here and that's what dependency inversion is dependency inversion is a strategy of depending upon interfaces or abstract functions and classes rather than upon concrete functions and classes so instead of writing all repository implementation year I've written auth repository that comes from the domain layer this way I'm depending upon the interface rather than the concrete class the concrete implementation so dependency inversion helps me to segregate my domain and data layer so that they're both independent of each other so this way we following the solid principles the D in solid principles stands for dependency inversion not dependency injection even though dependency injection is a design pattern where we inject dependencies to particular classes that doesn't come under solid principles so this is all the explanation I had for clean architecture and solid principles now that we've understood this let's format a code a little bit for example over here we are using service locator. register Factory again we're doing service locator. register Factory again we're doing the same thing instead what we can do is remove the service locator remove the semicolon and do service locator. register Factory dot dot and even your dot dot so this way both the objects are linked together and similarly we'll also do it over here dot dot then even here we'll do that dot dot register Factory dot dot register lazy Singleton and that's all this just looks cleaner in my opinion and if you want you can also add comments saying that this is the data source this is the repository this is the use cases and this is the block so everything looks good in our application right now let's move to the the next feature which is persisting the odd state in our application that means if the user is logged in we want to keep them logged in so there are two ways to do this task the first way is to use the super base built-in stream that will let me know whenever the user signs up signs in or signs out the second way is to use a session so whenever I log the user in or sign up the user and restart my device you see we get this map looking kind of thing that is a session that is being printed out I'm going to take use of this session to check whether the user is signed in or signed out if there's no session that means the user is not logged in and if there is a session that means the user has logged in so I'm going to close this I'm going to close the in dependencies file go to the Explorer and in my data sources I'll get started so the first thing I need in my interface is something known as a session and that comes directly from super base and it's going to be null because if the user is logged in we're going to get the session if the user is not logged in we're going to return null and this is going to be a getter and we're going to call this current user session then obviously I need to implement this so I can quickly do command full stop create one missing override and I'm actually going to take this right at the top you can put it wherever you want it doesn't carry much meaning I just wanted to put it up over here now to get the current session all I need to do is superbase client. do current session and with this I'll have a session that's nullable returned so you might think we're done we just need to take this Au remote data source current user session and pass it down to repository use case and then we can check if the user is present or not but that's not what we're going to do that's because the current user session is only going to give me the ID and the email of the user in our scenario it's probably also going to give us the name but what if we had more Fields that's not a viable solution so using this current user session what I'm going to do is fetch the user data from the database so that I have the most upto-date information about my user so maybe you expand the app further and you want to add update user so you'll be updating the user in the database itself in the profiles table you won't be updating the au. users part right so to get the latest information about a user we have to contact super based database so we are going to implement a method for that as well so below login with email and password I'm going to create a new future with the return type of user model again but this time it can be nullable make sure that the user model is nullable not the future because a future is going to be returned no matter what the user model however can be nullable and then I'm going to call this get current user data and this is not going to have any parameters because I obviously have the uid of the user I'll get the uid of the user using this session and of course I need to implement a method so let me create this missing override now in this again we're going to do a very similar thing as we did before we're going to have an async function then a try and a catch block whenever I catch an error all I need to do is throw a server exception and the message should be e.2 string now how do I contact the superbase database to do that I can just do superbase client Dot and you see we have o we always used o over here but instead of using o now we can do from when we specify from over here we need to pass in the table so superbase client. from directly talks to the database we don't have to do something like superbase client do database or anything like that we can directly do do from from that means we're talking to the database and here I can pass in the table the table I want to talk to is profiles so I'll correctly spell that make sure it matches this table name then I need to get all the fields right so I'm going to do select and just doing select will get me all the fields because by default it has Aster risk as the value as the risk means that it's going to get all the values however if you want a particular value you can specify it over here for example if I just want the ID of the user I can specify it or maybe I want the ID and the name of the user I can specify that and there shouldn't be two separate strings instead you should just mention ID comma name however if you mention asterisk or don't mention anything it's going to take asterisk by default that means we need to get all the data from the profiles table by all the data I mean all the columns here you're only specif specifying what columns you need to get next you need to specify what row data do you want to get and if you don't specify any row data that means you'll get all the data from super base but we only want the data of one user right the current user who's logged in so I can do dot EQ that stands for equals and then I need to pass in a column name and the value so what user do I want I want the current user and I get the current user by using the session and session is going to give me the ID of the user which is our primary unique identifier in the table so I can use that I can say that the column name should be ID and the value should be current user session dot user do ID and this way I'm getting the data of the user whose ID matches this ID so from the perspective of super base what's happening over here is I go to the profiles table and from here I decide what columns do I want to get do I only want to get ID do I only want to get the name do I only want to get updated at field what column do I need to get and if I don't specify anything it's by default going to take Asis that means I get all the columns and then we need to specify what rows we want to get what particular user data do I want now if you don't specify anything it's going to get you all the fields but I do want only one field and that is our current user to get a current user we have the session variable that will help me get the ID and this ID luckily is a primary unique identifier so I can just use that ID to get one particular user data and I don't have to be concerned that I'm getting the wrong user data so now I can do a wait and store this in a variable let's call this final user data but here's the problem what if the user is not logged in in that scenario it can throw an error to us so I can take the precautionary measure over here you see when we try to access the user I say that current user session is not null but I cannot decide that the session can be null depending on the status of of the user if the user is logged in it's not going to be null if the user isn't logged in it's going to be null so I can check here if current user session is not equal to null then I'm going to run all of this code and if the user is not logged in I want to return null I have the user data with me and you see it's a list of map string comma Dynamic and make sure to put await over here if we put await we get a list of map string comma Dynamic if we don't put await instead we'll get postgress filter Builder etc etc so make sure to put a now based on this user data I want to return a user model so I can just do return user model from Json and pass in the user data but this is a list and this accepts map of string comma Dynamic to understand our next step we must first understand why is this giving a list of map string comma Dynamic the reason it is giving that is because there can be times when we get multiple user data for example if I hadn't mentioned this equal to filter our code would just be this and even then my return data type is list of map string Dynamic we getting a list because there are multiple users map that I'm getting my data looks something like this a list where there is one user data map a second user data map a third user data map but since I've already put equal to I know I'm only going to get one user data so this list is only going to have one element only one map so I can just do user data do first to get the first element in the list and then I can return that and that's my entire function of get current user data so since our data source is now over I can close this and go to The Domain layer to write a new method in our interface and that method is going to be current user so it's going to be future either failure or we going to get a user again but this time it's going to be current user and again we're not going to have any parameters so that's good now I can save this file go to the Au repository implementation and here fix this error by creating one missing override now I can take this function and put it somewhere at the top that's where I prefer it again it doesn't matter where you put it then I'm also going to put async over here I can call the get user function again so after calling the get user function I can return the call to remote data source. get current user data but I'm not going to do that the reason for that is I need to return a failure if the user is null because there is a possibility that a user can be null let me show you what I mean if I have a call made like this final user is equal to await remote data source dot get current user data okay so this user model can be null right and the bound of this get user function is future user it is not future user that can be nullable if that happens this will disrupt this entire function so I'm not going to reuse this function instead I'm going to write this from scratch and if I'm writing this from scratch it means I'll have to put a TR catch block again without fail because if I don't write it I'll crash my application because from get current user data we might throw a server exception so that's very important so in the catch block again I'm going to put on server exception then I want to return left and then I'm going to return failure e do message now the only thing I need to do is if the user is not null I want to return right otherwise it's a failure so I can check if user is equal equal to null that means I want to return left and then again I'm going to pass in Failure saying user not logged in now if the user is not null then I can just return right with user pass to it perfect so that's my entire function now if I go go down I disrupted this function a little bit so let me fix that and there there we go Au repository implementation is now done the next thing I want to get into is the use cases here I want to create a new use case saying that current user is there or not so I can create a new file current uncore user do Dot and here I'll start writing my code for current user so it's going to be a class current user which implements use case and then I'm going to pass in a success type so if it's successful I want to return a user that comes from the domain layer and the parameter has to be no params that means there is no parameter now how do I Define no params what I can do is create a class no patterms that takes nothing so it's an empty class and then I can pass no patterms like this okay and now I can implement the missing override but here's the thing think about it no patterms can can be the parameter type of multiple functions right there can be multiple functions that do not require any parameter so what I can do is take this no parms and put it inside of use case so after I've declared my interface I'm going to put in my class of no patters and in current user I'm going to import this no patterns and it's automatically done when we import the use case. do file I'm also going to remove this FP do dot file and import the normal FP do do package then I want to write async over here and just return a wait and now I need the auth repository so to get it again I'll have to create a Constructor we've gone over this multiple times now and we're going to have current user this do Au repository now I can take this Au repository and call the current user function now I can close all the save files over here and move to the presentation layer which has o block and in this O Block I want to add another use case from The Constructor which is current user and it's also going to be a private variable and then we're going to require this from The Constructor now after that done we need to create an event to check whether the user is logged in or not so let's go to the Au event do file and here create a new class and that is going to be final class o is user logged in now you can name this whatever you want I'm just going to name this now in this class also we don't need any Constructor arguments so I'm directly going to go to O block and register my event so it's going to be on or is user logged in then I want to run a particular function and that is is user logged in then I'm going to take this function name and create a function out of it so it's going to be void is user logged in then we going to get an event of au is user logged in and an emit which is going to be of the type emitter or state again and it's going to be an async function now if this is getting too long you can just put a comma so that it's formatted properly you can do that for other function as well well after that in that function you can call the current user class so we can just do this and now it requires no parms class so I can just pass in no parms like this there we go then I also need to await it and I'm going to store this in a result variable and this result is also going to be of the type either failure user so I'm just going to do result. fold now in case of failure I want to emit o failure and then I'm going to pass an l. message and in terms of success I just want to say that hey this was a success so I'll do all success and we do have the user with us R is a user so I can just pass in an R now this formatting looks a bit weird to me so I'm just going to shift it like this so our O Block is now ready I can go to the Explorer and we see an error we see an error because in the in a dependencies do. file we have registered the O Block but we forgot to put in our new use case which is the current user so let's go to the use case part here it is and then we going to do register Factory and we going to register our current user then obviously we need to pass in a auth repository so to do that I'm again going to pass in service locator put in some commas to format the document and there we go then here I need to pass in the current user and I'm going to pass in the current user as service locator again so all of this looks pretty solid to me the last thing I have to do is go to the main do. file and run the function now to run the function I need to get access to this Au block and then call the Au is user logged in event to do that I'm going to go to the main. do file and convert this my app to a stateful widget so I'll press control shift R and convert it to a stateful widget once I convert it to a stateful widget I'll get access to the init State method in this init State method I'm going to do context do read and I'm going to read the O block and here I'm going to add my new event which is O is user logged in if you want you can actually name this Au current user or whatever but I think this is fine for me now just to see if this runs or not what I'm going to do is go to the Au blog class and here whenever we get a success I'm going to print that success out just to see if it's the right thing so I'm going to print R do email then I'm going to restart my entire app open the terminal and I don't see any email being printed out let's try to do this a bit differently I'll do R do ID then we can restart the entire app restart this and we get the ID of the user if I do r. name let's see what we get I'm going to restart my app and then see the terminal it says Rage ravat that's fine so why aren't we getting the email of the user and the reason we're not getting that is because we've not stored the email in our database so what can we do to get the user email now most likely you won't be needing the user email but just to make sure you have the latest and greatest information what you're going to do is go to the data source Au mode data source and over here when you do user model. fromjson you can update this user model to also have the email now since this class has all the fields as final we can't update the particular field right if we go to a user class you see all of these are final final variables cannot be changed so I cannot change any aable of this class directly what I can do is Implement a copy with method that will allow me to change the properties of this class so to implement a copy with method what I can do is click on this bulb icon but you see we get WRA with blog Builder and everything related to a block that's not what I want and we probably get this because we are extending from a class but if I go to the parent class click on this bulb icon I get the option to generate copy withd now I can take this C copy with cut it from here this shouldn't have much logic I can remove this and paste my copy with function over here obviously I need to change this because we need to return a user model not a user and this way it's all fixed now our user model also has a copy withth function I can go to the auth remote data source and then do dot copy with the reason we get copy with is because this particular function is returning a user model and on user model we' have created the copy with function so now on copy with I'm going to pass in my email and to get the email I can do current user session dot user do email so with this we are returning a user model which has an email now I can restart the entire app go to my terminal we see ran being printed out that's good I'm also going to print out email now and if I restart I see my email being printed out perfect so everything seems to be working fine in this scenario now the next thing I want to do is depending on the user status of whether they're logged in or not I want to display the login page or the homepage and this should be fairly easy to do I can just use a block consumer again and if the state of O Block is Success that means the user is logged in otherwise the user is logged out but here's the problem if I use Au block to get the user information what will happen when I need the user information in other features for example when I try to upload my own blog I'll need the user ID of the user and to get the user ID I'll be using Au block now I said Au block and all the things that are defined inside of this o feature should only be usable in inside of the Au feature it cannot be used in some other feature in our application so Au block is definitely not a way to get the user information instead what I can do is Define an app wide user which can be usable across all the features in our app so I'll not be using the Au block to get the user data instead I'll be using that app wide user that we created now to obviously to purist state in our application we will need to use block but for this app wide user I'll be using Cubit block and Cubit are often interchangeable and I'll be using cubid because I just want to make this part very easy now the question becomes where should I create my app wide user Cubit now obviously I need to do that inside of the core folder right because core folder contains things that are sharable across all the features in our application and in the core folder I'll be doing it in common in in common I created a separate folder called wigets because there's going to be another folder called cubits so this is going to contain all the common cubits across all the features in our application or at least many of the features and to create a cubit I can rightclick and click on new Cubit here it asks me the name of my Cubit I'm going to call this appcore user and then hit enter so here as you can see it successfully generated app user Cubit it generated appuser Cubit do file and app user State file the only thing I didn't like is that it named it cubid I want to name this something else so what I'm going to do is write click rename and I'm going to rename this to appor user because there can be multiple cubits over here right I want to be very specific calling this app user now in the app user state there's only one state app user initial app user initial should be the initial state of the application that means it is the state that shows that the user is logged out so naturally I'll have to create another class called app user logged in this is the state it is depicting the user is logged in and then I'll have to extend the app user State now if the user is logged in I'll obviously want some information over here right and that's going to be the user so I'll do final user but you see I'll have to import user from the authentication folder now anything that is present in core can be used in other features but core cannot have inputs of classes that are defined inside of another feature so to tell this simply core cannot depend on other features but other features can depend depend on core so that means the user cannot be used because the user is defined in the authentication feature now what should I do so that I can use user over here so it only makes sense for me to take this user out of the authentication feature and put it inside of core so I'm going to comment this for a minute going to save this close all the save files and then go to the Au feature the domain layer entity and I'm going to take this entire folder out in the common folder of the core folder and then I'm going to move it over here let do do all the refactoring and then I only need to save all the files so I can quickly do that after you've saved all the files you can close all the save files just to make sure you've not closed any unsaved file and now the user entity belongs in the core folder that means this user is reusable across multiple features and it makes makes sense right if I have the blog feature where I want to get the user ID I obviously need to get access to this class so I'll be accessing this class's ID so this user class has to be in the core folder now you might wonder that hey our domain layer doesn't have an entity anymore is that fine and that's totally fine there's no compulsion that an entity should be present an entity is there so that your code gets more structure and the structure is being received because I'll be using this user class in the O feature as I said in the app user state core cannot depend on other features but other features can depend on core so our o feature is now totally dependent on this score so I hope you understood this it was a lot of refactoring and I purposely did that so that you understand the fundamentals of clean architecture and then modify it on your own to suit your application needs now I'm I'm going to uncommon this line and then going to import this user that comes from the core folder then I'm also going to name this user and then I'll take it from The Constructor app user logged in this do user if you want you can make this Constructor a const by making its parent class app user State a const now over here I'm going to remove the import of block the import of meta and then directly going to import the flutter block pack package now in this one thing that's correct is that app user Cubit has the initial state of app user initial now I only need to add a new function and that is to update the user so what I'm going to do is void update user and I'm going to take a user that can be null and then in this function what I'm going to do is check if the user is null that means the user is in the initial state so so I'm going to emit app user initial State now you might be wondering if the initial state is app user initial why are we emitting a new app user initial State and that's because if the user logs out the user is again going to be null so we again send them back to the initial State because initial State represents the logged out State then we going to have an else condition if the user is not null in that sense scenario I want to emit app user logged in state and then I'll pass in the user that I get from the parameters then I can save this and let's see why we get an error in the app user State we get this error because immutable is not Define let me quickly fix that there we go so our app user Cubit is now set up we don't have to do anything else because Cubit doesn't work on the concept of events block does in in Cubit you can directly call the function now the next thing I want to do is take this app user Cubit and connect it to the O Cubit why because I want to call this update user function right when this update user function is called our app user Cubit will update and we'll have a new state we'll have a state of whether the user is logged in or whether the user is in its initial state so I'll go to the O block and here I'm going to have a new block final app user and it's not a block sorry app user Cubit app user Cubit will be a private variable the same thing that we have done before multiple times and then I'm going to set app user Cubit private variable to app user Cubit awesome now when do we want to update the user we want to update the user whenever they sign up whenever they login and whenever we check if the current user is present or not not because if the user signs up we want to send them to the homepage if the user logs in we want to send them to the homepage if the user is logged in we want to send them to the homepage so in all three of the events we'll have to call app user Cubit do update user so at the bottom I'm going to create a new function and this is going to be a very reusable function and obviously a private one we're going to call this emit Au success and here we're going to take in a user and we also want to take an emitter of all state because we'll be emitting some form of state from here and the state we'll be emitting is all success so let me type it out Au success and then we need to pass in the user that we get from the parameter perfect now that's not all this function does this function is also going to update the user so it's going to have app user Cubit do update user and then I'm going to pass in the user over here now I'm going to replace all the emit OD success lines that are present with emit OD success like this then I'll pass in R which is the user that we get from here and the emit which we get from here and similarly we're going to do it with everything so let me copy this paste it over here and instead of using curly bracket I'm going to put an an arrow function and this is a user so let me put user then we can again go up and we're going to have an arrow function with emit all success passed over here like this that looks awesome so what we are doing is emitting o success and updating the app wide user that is the app user Cubit whenever we check if the user is logged in whenever the user signs up or whenever the user logs in now I'm going to go to the in dependencies and add a new parameter of app user Cubit so first we'll have to register the app user Cubit which I'm going to do over here I'm going to write here core and whatever dependencies are related to core are going to go over here and then I'm going to do service locator. register lazy Singleton we're not going to do factory because even in the app user Cubit it has to maintain its state throughout the lifetime of the application and here we going to pass in the the app user Cubit now I can go down and just pass in a service locator like this now I also need to create an instance of this app user Cubit which I'm going to do in the main do. file so here I'm going to create a new block provider and it is going to be on top of the O Block I don't think it would make much difference and here I can just pass an app user Cubit and that's all so I've registered a block provider which is app user Cubit now all of this looks good we have called the ad o is user logged in so what's going to happen is this event is going to get triggered so in od block we're going to have this event running so this function is going to run and here we're going to call the current user function so it's going to check and let us know whether the user is present or not if the user is not logged in we're going to get a failure but if the user is logged in it's going to run this method emit OD success and that updates the user in app user Cubit so I can use the app user cubit in the main do do file to display a login page or a homepage so I'm going to wrap this login page with a block selector I'm doing blog selector because I only want to catch one state in app user Cubit and that is the app user logged in state so I'm going to have app user Cubit the state is going to be app user State and the selected state is actually going to be a Boolean why because in the selector I'm going to check and return if the state is app user loged in and this doesn't have to be a const anymore the const is going to come over here return const login page so this block selector is going to look for app user Cubit and whenever the state is app user logged in it's going to run this Builder and in this Builder I'm going to check if the state is true this state is letting me know if the user is logged in or not so let me rename this to is logged in then I'm going to check if the user is logged in then I want to return a homepage right and I don't have a homepage widget created yet so what I'm going to do is just put in a scaffold with body and a center text that says logged in we'll update this later on when we create our homepage but for now the scaffold is good enough I'm also going to put this as a the constant so that all the warnings are gone now I'm going to restart my entire app and as you can see logged in shows up so that means our entire authentication logic is working fine now there is a bit of a refactoring I want to do if I go to my Au block you see in the is user logged in part I forgot to emit an au loading State and if you see in the signup I have emit or loading even in the login I have emit or loading so I need to remember to put this emit off loading every single time but what if I don't have to do that what if as soon as we get an event the loading indicator starts automatically can that be done yep that can be done we can add a catch all loader for all o events this way we don't have to explicitly emit o loading before operating on each event this way even if we forget to put emit off loading it doesn't matter because we have already started the loading event so how should I go about doing this well in the beginning I can just catch an event saying on o event so if I get any type of event I'll just say that hey go ahead and emit o loading event so here the first part is going to be an underscore because it doesn't matter to us and then an Emit and here I'm going to emit Au loading so this way no matter what event runs Au side up Au login Au is user logged in this is going to run first so Au loading is going to begin and this way I don't have to mention o loading over here or over here so that's a nice refactoring we could do we catch all the O events over here emit the loading State and then we can move to some other event to give you an example if the user calls the Au signup event this event is going to get triggered so o loading state begins and then this function runs OD sign up and then all of this get gets executed and then finally we emit o failure or o success depending on what happens so I hope this was clear now I'm going to close all the save files over here and I think we are done with the entire o section we covered a lot over here and we understood the clean architecture thoroughly tillar so if you were just watching this tutorial to understand clean architecture I think you can pause the tutorial over here and Implement clean architecture in your own application however if you want to continue with me and build the entire app you're welcome to do so now we're going to get into the blog feature of our application now let's see what's next for us so let's get back to our flowchart and over here let's see what we' have completed so initially the app begins then we check if the user is authenticated if the user is not authenticated we want to display the login page which we do and then there's a text that says do you not have an account if the user does not have an account we display the signup page and if the user has an account they can click on login and go to the homepage as of right now our homepage is just a text saying logged in but we need to replace that with the actual homepage so that's a work in pending now if the user is authenticated we want to check if the internet connection is present and if the internet connection is present we want to fetch blogs from superbase so this internet connection part can be done later on but for now let's just fetch blocks from superbase and to fetch blogs from superbase first we need to upload blogs to superbase and to upload blogs to superbase we'll need a homepage which will redirect us to a page that will allow us to add a new blog so everything points us to One Direction creating the homepage where we are going to display blogs and over there there's also going to be a button that will allow us to upload a new block so let's get started with it in the features folder I'm going to create a new folder called blog and in this blog we're going to have three subfolders data domain and presentation now in this presentation layer we're going to add our Pages folder and also the widgets folder in this Pages we're going to have our new page called blog unor page do. file now I'm going to minimize this Explorer and create a stateless widget and this stateless widget is going to be called blog page which is going to return a scaffold the body of the scaffold is going to display all the list of blogs and in the app bar we are going to display a title that says that this is a blog app and we are also going to have a button that will move us to the add new Blog Page and on that page we'll be able to upload blogs so I'm going to quickly pass in an app bar and in the app bar we are going to pass in a title so the title is constant text that says blog app if you have other name of your app you can pass it in if you have an image to pass in you can do that as well because title accepts a widget not a particular text then I also need a button to go to a new page to upload a new blog so I'm going to pass in an actions and in the actions I'm going to pass in the icon button the icon button is going to have an onpressed function and an icon the icon is going to be icon copertino icons I'm not using material icons this time copertino icons do add circled I like this design and obviously this is going to be a constant now what I want to do is take this block page and put it in the main do. file so whenever the user is logged in we don't want to return a scaffold instead we want to return this Blog Page and also this has to be a constant now I'm going to restart my entire app and if you see we have blog app showing here with this button now whenever I click this button I want to go to a new page that will give me a text field to add a title content upload an image for my blog and then upload my blog to superbase so let's get started by designing that page so what I'm going to do is open the Explorer and in this Pages folder I'm going to create a new page and we can call this page addore newor blog page. do then I can again close this Explorer and here we going to create a state full widget why because we going to have two text editing controllers and we need to dispose those two text editing controllers so I'm going to have a state full vget let's call this add new Blog Page and then again we're going to return a scaffold and here again we're going to have an AB bar and in this AB bar we're going to have a new button in the actions which is again going to be icon button the onpressed is going to be an empty function and the icon is going to be icons. unrounded so this is the button which when clicked is going to upload our block to super base now I can also create a route to this page which we've done before with the sign up and login pages so I'm quickly going to create a static route here which is going to return a material page route the Builder is going to get a context and we going to have add new block page also this has to be a const now I can go to the block page and whenever the user clicks on this add circled button I want to navigate from block page to add new block page so here I'm going to do Navigator do push and the route needs to be add new block page. route awesome now I can restart my app and if you observed we see a loading indicator the loading indicator is present because in our Au block we had passed a loading state for all our events so if I again restart you'll see for a second there's a loading indicator awesome that looks good now if I click on this Circle I also get shifted to a new page so that seems to be working fine now how is the design of this add new block page going to look like so this is what the design of this page is going to look like first we're going to have a container that allows us to select an image and then we're going to have multiple filters that one can select so these are the topics that your blog can belong to then we're going to have a title and the content of the blog so first we want to replicate this part this container so let me zoom in and show it to you so as you can see we have a dotted border over here now we can create this manually in flutter but it will take some code instead what I can do is install a package that does it so I'm going to press command shift p add dependency and then I'm going to add dotted uncore border package once that's added we can go in the scaffold of this add new block page and then specify the body the body is going to be the column because there are multiple vets that we want to lay down vertically then in this column the first child is going to be a dotted border and the child of this dotted border is going to be a container where we're going to specify the height and width so the height is going to be 150 so let me pass that in and the width is going to be how much ever width we get so double do Infinity then we're going to have a child with a column and in that column we are going to specify the elements of this container and the elements of this container are going to be these things the folder the spacing in between and the text that says select your image so here I'm going to pass an icon icons do folder open and if we save that much we see our icon over here that's looking good but I want to increase its height so what I'm going to do is set the size to let say 40 then it looks much bigger that's good the next thing I need is a spacing in between so I'm going to leave a size box of height let's say 15 and then a text that says select your image and here I'm also going to put in a style of text Style just to increase the font size of this text so it's going to be let's say font size 15 now to remove all the warnings all I need to do is set cons for this column because all of these things are constants now that we've completed this this looks good the only thing I need is to Center this column that we have and to do that we can just do main AIS alignment main AIS alignment. Center in this column and that will Center everything now if you see from the side there's padding to our container it's leaving some space from the edges we want to do that so we can wrap our entire container with a padding widget but if you go down and see even this topic selection part has padding on the left and right even this blog title and blog content text Fields have padding on the sides I want to change that so everything has the same amount of padding and instead of wrapping everything with padding I'm going to wrap this entire column this column with the padding widget and it's going to be ENT says. all 16 then we're going to come over here and this looks good the next thing I want to do is change this color of the border so I can specify the color over here and the color is going to be app pallet. border color there we go now the next problem is that this dot is very small I want to increase the length of this Dash so what I can do is specify something known as Dash pattern over here and this requires a list of double and here I'm going to pass in 10 comma 4 and obviously this list has to be a constant we can save that and when we come over here you see this is now looking much bigger if you want you can change this to let's say 20 comma 4 and you'll see the difference over here so you can adjust this based on what you want I think 10 comma 4 looks solid so I'm going to keep that the next thing I want to do is make the borders rounded to do that in the dotted border I can specify the radius and the radius is going to be radius. circular 10 and obviously let's pass in const now if I come back this looks more rounded but let's make it more perfect just like this one so what I can do is specify the Border type over here and the Border type should be border type. rrect and when I come back this looks better another thing I'm going to do is specify the stroke cap over here which is going to be stroke cab. round and when I do that it feels fully polished if you want to see what stroke cab. round does your the explanation you can read this and you'll understand now if you're wondering how I know what properties to put in that's because I've already created this in my demo application and to understand what exactly to put I just referred the documentation of dotted border and I was able to create this design so so now that our container is done let's get started with this chip part now there are two ways to display these things the first way is to use a row and a single child scroll view to display a list of chips the second one is using a list view Builder you can use whatever you want I think I'm going to use the row and single child scroll view so let me go down here and then I'm going to pass in a single child scroll view via scroll View that's because there are not just three chips over here there are actually Four chips so we want to be able to scroll if there are more elements and select those elements so here obviously by default single child scroll view has a scroll direction of axis. vertical I want to change the scroll direction to axis do horizontal then as a child we want a row because everything should be aligned horizontally and the row is going to have children and in the children I'm not going to pass any list like this what I'm going to do is create a list let's name our topics over here my first topic is technology the second topic is business the third topic is programming and let's add a fourth topic which is let's say entertainment after that call the map method on this so what map is going to do is Loop over each and every one of these list elements and put them in a container and this is the container we want to put them in now you can create this container from scratch using the container widget but what I'm going to do is utilize the chip widget that flutter provides us with so the label is going to be text and then we're going to pass e also just so that the errors are gone I'm going to convert this entire map to a list okay so this map function gives us a an itable I'm converting this itable to a list so that we can pass it as the children to the row so what's happening is we have a list then we're calling the map method on it so we Loop over every single one of them so e contains in the first iteration technology so Chip is created with the text of technology in it and it is displayed on the screen so if I restart my app you see we have these chips displaying over here now I want to design these chips and to design them I can pass the design over here but instead of doing that I'm actually going to go to the theme. do file and set up a global theme for this chip so here I'm going to pass in a chip theme and this chip theme requires chip theme data which I'm going to pass in the chip theme data is going to have a color and then it requires something known as material state property and then we need to specify the color so I'm going to do material state State Property all once I do that I can directly pass in a color and the color is going to be app pallet do background color so the Chip is going to have a background color as its main color now if I come back over here we don't see any difference so let me restart the entire app and when we come over here it matches with the background the other thing I need is that the bord should not be present by default there should be no borders so I can pass in side Border Side do none Also let's put a Conway here and then restart the entire app now when I come over here you see all the Border has been removed from our chips now I know you'll say that there is border Behind these chips right we can see that over here there is border but the reason we have remove border is because if a chip is selected you see there is no border for the the chip if the chip is not selected then there is a border so we need to achieve that so we can again go to add new block page and here specify the border so I can specify the side to be Border Side the color will be app pallet do border color and then later on we will specify over here that if a chip is selected then only this border color should be displaying otherwise we don't want to display it but anyways this looks cool now the next thing I want to do is leave some spacing from the top so I can do that quickly by leaving a constant size box of height 20 after that this looks good now I only need to leave some spacing between these two chips and to do that I can wrap my entire chip with a padding widget so I can do padding and let's leave padding of five pixels then I'm going to come back over here and this looks much better perfect the next thing I need to put in is these text Fields And if you remember in authentication we created a widget known as Au field that looks very similar to this actually it's the same thing the only difference is it's working that means if we want to add more than one line this text field is going to expand let me show you a demo so here we have block title we pass in something in the block content let's say I pass something the block content can be greater than 100 characters or something so when it exceeds the length it just creates a new line in the text field we want to achieve that as well so we're not going to be using the text field that's present in the O feature and technically we shouldn't because we're doing feature-- wise development each feature should have its own stuff otherwise it should be put in the core folder so what I'm going to do is that in our Explorer I'm going to create our own widget and let's call this this blog uncore editor do do and in this blog editor I'm going to create a stateless widget so let's call this blog editor then we're going to return a text form field and the text form field we're going to pass in a controller so we're going to take the controller again from the Constructor let's take it in and it's very very similar to our Au text field so let me pass that in quickly other thing we'll be requiring is an hint text and I'll require that from the Constructor to then I'll pass in my controller over here in the decoration I'm going to pass in input decoration then I'm going to pass in the hint text and the hint text is going to come from the Constructor to now I'll go back to our original app and nothing changes and that's because we've not call the blog editor class in the add new blog page so let me add that right after single check child scroll view so we have blog editor now we need to pass in our controller and hint text so the hint text is going to be pretty simple we're going to call this blog title and for the controller we'll have to create that on the top so we'll have final title controller which is equal to text editing controller and since we here let's create another text editing controller for the content so we going to call this content controller now before I forget I'm going to dispose these things off and I'm just moving quickly over here because we've done all of this in the authentication page too so I don't want to waste much time over here so after the dispose method is called let me go down and fix it by passing title controller awesome now if you see blog title shows up over here and that's looking good if you're wondering how the styles were automatically applied that's because in our theme. do file we've passed in the input decoration theme so that's working fine for us now the next thing I want to do is leave some spacing over here so I'm going to leave a constant size box of height 10 then again I'm going to take all of this and repeat below the block title so we're going to have a block content here and we're going to call this content controller then save it and we have block content showing up as well now if I type anything you see I don't go to the next line I want to go to the next line as soon as this typing is over to achieve this what I need to do is go to the blog editor widget and here specify Max lines as null once I do Max lines as null what happens is when I type something and it exceeds the limit it goes to a new line and there and then it can go to multiple lines if I want so you see this is pretty good for our application but here's the problem if we exceed this screen height it gives us this render flow error so to fix it I want to wrap this entire widget this entire column that we have with a single child scroll view so I'll wrap it over here and then it should be all right there we go so our entire design of the app looks good enough the only thing I want to do is whenever I click on one of these chips it should be stored in a list because we need to store all of this data in database right so if I click on any of them I want to store it in a list and also display that yeah you've selected this so first of all I'm going to go ahead and create a list at the top it's going to be a list of string and I'm going to call this selected topics initially the list is going to be empty but as in when the user selects a particular chip We'll add it to this list then I'm going to wrap this entire chip with a gesture detector widget I'm not going to wrap this padding with a gesture detector widget because then if I click over here it's still going to select this chip I don't want that only if the user clicks on this chip I want to select it so I'm going to wrap this chip with a gesture detector widget then we're going to have an ontap and in the ont I'm going to do selected topics do add and then I'll pass in E because e is the topic that we have right We're looping through all of them so e is this string so we'll add that in selected topics and obviously we need to call set state so we'll do that set state will rerun this entire build function and that's exactly what we want now if I select something we don't see anything but if I print selected topics over here we should be seeing something so let me do that again you see we have technology and business both in our list because initially I clicked technology and after that I clicked business so that's looking good but what if I want to remove a chip too so if I click on business again what it's going to do is add it to our list again so we have technology business and business but what I want to do is if business already exists in my list and the user clicks on it again I want to remove it from my list so I can just have a condition over here if selected topics contains e so that means our list already contains a particular Topic in that scenario I want to do selected topics. remove e and if the selected topic does not contain that string I want to add it to my list and then I want to call set State this looks good now I can restart my app actually there was no need of restarting but anyways I click on technology I click on business now I'm going to open my terminal and I see technology and business and if I click on technology again we only have business in our list now so that's amazing now I only need to do one last thing for this chip if the selected topic contains that E I want to display a pink color otherwise I want to display no color so I'm going to remove this print so that it doesn't give me any warnings and then in the color I'm going to pass in the color of the chip so I'm going to have a condition here if selected topics contains e then I want to pass in constant material State Property all and then pass in the value the value is going to be app pallet. gradient 1 otherwise if it does not contain anything I want the default color to be there and for the default color to show up I'll just pass in null and now if I come back you see technology programming everything is highlight and if I click on programming again it's not highlighted so our logic seems to be working fine but there's only one issue I have the Border color Still Remains even if the chip is selected so I want to make changes to that so over here I'm going to again check the same thing if selected topics contains this topic then I don't want any border color so I'll pass in null and if selected topics does not contain then we want the Border color to show up and this way you see our app feels a bit different so this is the entire UI the next thing I want to focus on is selecting an image from the gallery so let's get into that so to pick a file in flutter we're going to be using the image picker plugin that's provided on on pub. dev so this is the plugin we'll be using and it's directly provided by flutter themselves so I'm going to copy this and press command shift p add dependency and add image picker now the next thing I want to do is see if there's any installation processes and there is an iOS part so if you're following Along on Windows you can skip this part because there's no configuration required for Android for iOS however we do need to do something we need to go to our info.plist file which is located under iOS Runner info.plist and add these three things so I'll press command P type in info. P list and make sure to select iOS Runner not Mac os/ runner go in there and here you need to add two or three keys so I'm going to copy this part and paste it two times below then I'm going to copy this NS photo library usage description key and replace it with the UI mean storyboard file and then we need to provide a description of this key so I'll say that photos from gallery required now obviously if you're sending this app to app store for review you cannot write this it needs to be more detailed of where it's being used in your application but for us this is fine the next thing we need is in this camera usage description if your app needs access to camera this is what you'll be needing so our app doesn't require camera but I think you might want to implement the photo from camera option so I'll just pass it in and then I'll say photos from camera now there's a third key which is NS microphone usage description which helps us get access to the microphone now we won't be needing access to the microphone because we'll not be recording videos we only need images so these two are fine we're done with the installation in iOS as well I'm going to terminate my app processes and restart the entire app then I'm going to close all the save files open the file explorer go to the core folder and in that I have utils in the utils folder I'm going to create a new file called piore image. do and this is going to Ain a utility function of pick image because pick image is a function that can be called in the block feature it can also be called in other features in our app for example if your authentication requires the user's profile picture you'll be using this function over there so let's go ahead and Define the pck MH function it's going to return a future file and this file needs to come from IO not HTML so keep that in mind after that I I'll put a question mark because it can be nullable and we'll understand why it can be null in just a minute then I'm going to call this function as pick image and then it's going to be asynchronous after that I'm going to have a try and catch block because we're going to be making asynchronous calls now if there's an exception we're going to return null if there's an exception it means that user probably didn't give us access to the files or the user did not select any file after opening the gallery after that we're going to call the image picker plugin so we have image picker let's create an object do pick image and the source is going to be image source. gallery we won't be allowing camera in this application however if you want you can pass in camera to get access to the camera of the user after that we can pass in await and store this in a variable and this is going to be x file this this is of the type x file 2 which can be nullable so I want to check here if x file is not equal to null if it is not null then I want to return a file which is made from the path of this particular file so this way we are returning a file and if the x file is null then I will obviously return null so that's our entire pick image function which we can re use again and again now I'm going to close this open the Explorer and go back to our block feature so in the presentation layer Pages add new block page I'm going to integrate this function so at the top I'm going to create a new function called void pick image or if you want you can name this select image just so that there's no confusion after that again we're going to call async because we'll be calling the pick image function that that comes from the core folder after that I'm also going to aade this and I'll get access to the picked image now this picked image is a file that can be null so again I'll have to check if the file is null or not and if the file is not null then what do I want to do what I want to do is display it on this screen to do that I'll have to create a variable over here which is of the type file and it can be null because initially the user has not selected any image so initially the file image is going to be null and this is the image variable that we'll be using to display the image on the screen so I can take this image and then I'll check if picked image so the image that the user picked from our Gallery is not equal to null in that scenario I want to set State because I want to rebuild the entire build function and then I'm going to to set image equal to this pick image and that's all if you want you can just keep it like this image is equal to picked image because if this picked image is null image will again be set to null and I don't think the build function will rebuild if the image variable has the same value however I would like to keep it this way because there is a condition where our logic will fail I'll show that to you in just a minute I'll take the select image and put it in the gesture detector of this dotted border because whenever the user clicks on any part of this dotted border year or year we want the gallery to open so I'm going to wrap this entire dotted border with a widget called as gesture detector then I'm going to pass the on Tab property which is going to be select image like this then I can come over here and click on this part and it asks me if I would like to give permission to blog app to access the photo library I'm going to give it full access then I'm going to select a file and the file is selected but it's nowhere displayed on our screen because we have not put the rendering condition so here I'm going to do that I'm going to say if image is equal equal to null in that scenario I want this so if the image is null then I want all of this to display but what if the image is not null that means the user has selected some sort of image in that scenario I want to display the image so I'm just going to reverse this condition so that I can write my logic over here so image is not null then we want to do something otherwise we'll display a gesture detector so here I'm going to pass an image. file and then pass in the image also this has to be a non-nullable thing then I can save it and we see our image displaying over here that's looking good but I still want to make some changes over here the first thing I want to do is decrease its height and take the entire width so I can wrap this with a size box widget where I'm going to specify the height to be 150 and the width to be double do Infinity so here it is that's not looking good if I decrease the height of my Widget the image is not taking the entire width so so to make it take the entire width in the image. file argument I'm going to pass in fit and the fit is going to be boxfit do cover and this way it takes the entire width of the screen another thing I want is that this border radius should be rounded if it's rounded it's going to match with the vibe of our entire application so I'm going to wrap this image. file with a widget known as clip rrect and then it will allow me me to pass in Border radius which is going to be border radius. circular 10 let's say then I'm going to save it and there we go this looks good now if I click on this again we're not able to select an image again so we can wrap this sized box with the gesture detector widget as well and then set the on Tab to be select image it's a reusable function you see now if I tap over here I can select another image so let me select this and there we go now coming back to our select image function here I said that the if condition is an extra logic and in one scenario this if condition is going to help us let me show you how it can help us so right now if I select an image and change it it works fine but what if I open the gallery click on cancel in that scenario the image goes away the image goes away because the picked image becomes null because over here I said that the x file can be null and if it is null we returning null or an exception will occur that will return null so our image again becomes null and as a result this logic rerenders so we are checking if image is not null but image is null so all of this logic runs and we see this part again so we do not want that and that's why we put an if condition over here so if pick image is not null only then we want to change this and this way if I change it works and if I click on it click on cancel this image stays the way it is so this if condition works as a safety precaution now you can adjust it the way you want your application to run but this is the way I want it to be so our entire designing page part looks good now the next thing I want to to do is whenever this button is clicked I want to upload all of that data to super base to do that first I'll create a new table in super base called blogs just like we did with profiles and after that we can get started with the data layer uploading all of the data to super base so let's go to our superbase dashboard and create a new table so to create a new table again go to this SQL editor and here we're going to write a new query if this doesn't show up you can just click on new query and and you'll be able to write your new query now again we're going to copy the same stuff from this blog Builder user management app so that we don't have to write it from scratch now I'm not going to explain the same thing so let's just copy paste it and just change a few things first of all I want to create a table for blogs so let me name this blogs and here I can sa for public blogs after that the blog is going to have a column called ID which is going to be of the type uu ID but it shouldn't be referencing o. users because this ID is going to be automatically generated one so I can remove this references o. users but yeah it is going to be not null and again this is going to be our primary key because because IDs are generally the primary keys in any table then we are going to have our column of updated at timestamp with time zone so that's good then we not going to have the username full name so I can remove that we also not going to have the Avatar URL so I can remove that and the website is also not going to be there what I need is a title so I'm going to have a title of the type text I'm also going to have a content of the type text then we also going to store the image URL which is going to be of the type text now you might be wondering that hey the image URL how are we going to get the image URL it is a file right and that file is stored in our device so what we are going to do is take that file and upload it to storage this storage will give us a URL which we can put in our blogs Table after the image URL we're going to have our last field which is going to be topics so these are the topics that the user can select technology business programming and entertainment but this topic cannot be a text right it has to be an array it has to be a list and it's going to be a list of string so we can pass in text followed by array meaning that the topics is going to be an array of text if you want I think even this will work so you'll get to know that this topics is a text array but I'm just going to specify it like this another field we require over here is the ID of the user who's posted this blog so right now I'm uploading from my device so I need to know which user posted that right and to do that I'm going to store the ID of the user I'm not going to store the name of the user because the name name of the user can be updated at any point in our application if you decide to add the update user profile functionality it can be changed so I'm not going to store the name of the user instead I'm going to store the ID of the user and that ID of the user will help us connect to the other database so if I go back to our database then I click on schema visualizer you see over here we had a profile ID which was connected Ed to o. users. ID now we're creating another table called blog which is going to have a poster ID or the user ID which is going to be connected to this profiles and we saw that this ID became a foreign key because this was the key that helped us connect to another table and similarly the poster ID that we're going to have here is also going to be a foreign key so I can just type your poster uncore ID and if you want you can call this user ID it is going to reference public. profiles table right earlier we had written references au. user this time we are referencing the public profiles table and we referencing a particular ID of that table so I can just pass an ID like this so poster ID is referencing public. profiles ID now if I need to be more specific what I can do is wrap this poster ID with the foreign key tag and and this way we are very specific that this is going to be a foreign key poster ID which is going to reference public. profiles and very specifically we are referencing the ID column of this public. profiles table and then we can remove our constraint because there's no constraint over here now another thing I forgot to do is mention the poster ID at the top so I'm going to have poster ID which is of the type text which I'll specify over here and then later on I'm saying that that this poster ID which is a foreign G is referencing public. profiles ID and I'm sorry I just realized the poster ID is not actually a text it is a uu ID and if you want you can also add not null you can actually add not null for the title as well and for the content as well because none of them are going to be null so yeah if you want to specify that this poster ID is referencing something and that it is a foreign key you must first specify it over here awesome so our table for blogs is now created then we set up the row level security we enable the row level security here we can just change that public blogs are viewable by everyone and then we can change the table name which is blogs again then users can insert their own blogs so it's going to be on the blogs table again this is also going to be blogs and we can say users can update own blocks so this looks good now we don't need a trigger over here right so whenever a new profile entry is created in signup o we don't want this procedure over here so we can directly remove this entire function that's good we do need storage in this one because we will need to upload the user image into our storage so we can just have insert into storage. buckets ID name so the ID is going to be blog uncore images and the name is going to be blog uncore images as well then we can copy this blog images and put it instead of Avatar every single place so after all of this is done I'm just going to click on run and hopefully it is a success and it is after that I can go to my table editor and here I should see a Blog table that is automatically created and you can see we have ID as a primary key and poster ID is a foreign key relation which references the public. profiles. ID now if we want to be extra sure what we can do is go to the database go to schema visualizer and we have a clearer picture so we have our ID which is of the blog and it's a primary key then we also have a poster ID which is referencing the ID in public profiles and this ID in public profiles is referencing au. users. ID so that looks good our table is created now let's go ahead and see if the storage bucket was created and yes it was blog images is present over here we do need to change something over here I'll click on this drop down edit bucket and as we can see this is not a public bucket no one can read any object without any authorization I do not want to allow this so I'm going to enable it and it will give you a warning I'm fine with that if you want you can look into additional configuration meaning if you want to restrict the file upload size so no one can exceed more than let's say 20,000 bytes or something then the allowed mime types that means you want to allow image video audio what so if you want you can add image JPEG SL image PNG so that only images are allowed and as you can see V cards are also allowed so we can pass in image/ asterisk and it will only allow me to pass in images but I don't want to do any of that I'm just going to click on Save and now my blog images bucket is public now I can come back to my code close this file and start working on the domain layer in the domain layer I'm first going to create my blog entity then I'm going to go into the data layer create a model followed by data source and then we can come back to the domain layer to write a repository so first things first let me create the entity The Entity is going to be blog. Dot and here it's going to be a very simple class blog which is going to have an ID then it's going to have the poster ID then we're going to have the title the content then the image URL then the list of string of topics then an updated at date time and that's pretty much it for now we will have an extra field over here but I'll get to that later on when we fetch the blocks for now I can just generate a Constructor for this so I'll create Constructor let me format this by putting a comma at the end and there we go cool now I can go to the data layer and create a model and that model is going to be called blog uncore model do do this class is going to be blog model which will extend our blog that comes from the entity now I'm going to press command full stop create Constructor to call called super and everything's going to be super do something now I'm not going to explain all of this again because I already did in the user model I hope you remember what all of this means now that our blog model is also ready I'm going to close all the save files go to the Explorer and then create a new folder in data layer called Data sources in this data sources I'm going to create a new file called blog unor remote unor dat _ Source do do file then I'm going to create an interface just like we did in the authentication part so I'm going to have abstract interface class blog remote data source and here we're going to start putting our method so the first obvious method is going to be upload blog so I can just have future and it's always going to return a Blog model let's call the function upload blog log and what is this function going to require well it's going to require a bunch of things right it's going to require the content the title the date time the ID and several other things so what I can do is instead of requiring each one of them I can simply ask for a Blog model which I'm going to do over here so we'll create a blog model in the repository layer and then pass that block model directly over here which I can use to upload the blog now let me create a class called blog remote data source implementation and that is going to implement the blog remote data source then I'm going to press command full stop and create one missing override here it's going to be asynchronous try catch again if there's an error we again want to throw a server exception and the message is going to be e.2 string in the tri blog we want to call superbase so again we'll be requiring super base from The Constructor so let me ask for that superbase client superbase client and then take blog remote data source implementation and call superbase client from the Constructor now I can take the superbase client and upload it to our database so to upload it we'll do superbas client do from so what table do we want to do the operation in I want to go to the blogs database let me see if I spelled it correctly blogs this is the one awesome and to upload a block to database all we need to do is call the insert method that's present over here once we do that I can simply pass in the object with the values now how am I going to get the values to do that I'll have to create a map over here and then pass in let's say the title so it's going to to be blog. tile then I'm going to have content which is going to be blog. content now instead of doing this over here what I can do is create a reusable method just like I did in the Au section I created the fromjson method in that because it was quite a reusable method even this part can be reusable right so instead of creating from Json I'm going to create to Json and actually I'll also have to create from Json because after I upload the blog I also want to return the latest blog from here so after I do insert it's going to give me the blog data that is the latest blog data so I'll return a Blog model created from that blog data so I'll need a fromjson method as well so I'll quickly go in the blog entity because that's where I'll be able to create my to Json and from Json class so I'll click on this generate Json serialization I'm going to remove everything from here and rest of the things I can copy for example two map from map and remove the 2 Json from Json after I've copied all of that I'll go to the blog model and in there I'm going to paste all of this so the two map is going to be just like this we're going to pass an ID poster ID title content image URL topics but the updated at is going to change because if you want to upload daytime to super base you don't have to do milliseconds since Epoch because then it would require a number because this is giving us an integer right to upload data to super base all you need to do is call the two ISO 8601 string method and once you do that here the return data type is going to be string however when it goes to to super base it's going to have a timestamp property so just make sure to change it over here then when we scroll down we want to have from map for blog model and then we want to return blog model over here the updated ad property here gives us an error because there's an extra parenthesis over here so let me remove that and it says that the error is gone however the error is there it's a logical error because if we do map updated at as int it's going to be an error because map updated at is not going to give me a number because I'm storing a string and in super base it's going to be stored as a Tim stamp and when superbase gives me the updated at Value again it's going to be a string so instead of doing all of this I'm going to do datetime do pass then I'll pass in the map update at this pass will convert a string to a date time and that's exactly what I want now just in case if updated is null what should happen if updated at is null then I want to return the current date time so I'll just do map updated at if that's null in that scenario I want to pass in date time do now and if it is not null then I want to pass updated at now another thing I would like to change here is the updated at property and actually for everything over here I don't want camel case I want the snake case so I'll do poster uncore ID title content image underscore URL updated uncore at even here we are going to have poster _ ID image uncore URL updated uncore at so that's looking good now now if if you want you can Implement error handling methods over here for example if this is a list of string meaning if map of topics is null then what do you want to do if it is null then I just want it to take a square bracket otherwise map of topics is enough and you can do the same thing for all the string Methods but I'm not going to do that and now instead of calling it two map let me call this two Json so that there's consistency in my naming in all my models and entities also this is going to be from Json so the two Json and fromjson methods are now ready all I have to do is call them in the remote data source so instead of passing in insert as this map I'm going to do blog do2 Json and then it will upload the map so whatever blog I get I'll call 2 Json so it will put in all of these things that's nice now after inserting it's going to return a Blog data to me so I'll just have final blog data is equal to a wait and it's saying Dynamic over here because I'm not called one method which is dot select if I do dot select over here it's going to give me the blog data which is again list map string Dynamic then based on this blog data I'm going to return the latest blog model which is return blog model. fromjson so it will convert this map into a Blog model and we've already seen that in the authentication section so I'm going to go quickly over this I'll just call Dot first and we're all done so it is uploading our block now you might feel there's some problem with this code because blog model accepts an image URL and we haven't even uploaded our image to the database so how are we going to get the image URL in this blog model and for that particular reason we'll have to add another method in blog remote data source which is just about uploading the blog image to superbase storage in the repository layer we're going to call the upload blog image function and the upload blog function both together in a single function but as of right now in remote data source we're going to create two separate functions for it we're not going to put the superbase storage call over here remember that data source is going to Simply list out all the functions and all of the functions are going to do just one task in repository layer however we're going to call the upload blog image which is going to take the file give us a URL and then we will update this blog model with the URL that super base gives us and then call this upload blog method so I hope it makes a bit of a sense right now if it doesn't let's just follow along with the code and I think you'll be able to understand this so let's create our function over here with which is going to be of the type future string and we're going to call this upload blog image now this is going to take in two parameters the first one is going to be the file that we want to upload to superbase and the second one is going to be the blog model why a Blog model is required because blog model has some things like the ID that it will require to upload it to a database so I'm going to make this named arguments and then I'm going to have required file import. iio file let's call this image and then we're also going to require the blog model after that is done the interface gives no error let's implement this in the data source implementation and here let's just format it correctly so we're going to have async then again we're going to have our try and catch block if there's an error we want to throw a server exception saying e.2 string in this function if it's still not clear why we are returning a future string it's because we're using async because of which this entire function becomes a future and from this function we're going to return the URL of the image so we're going to return a string to upload image to super base all I need to do is use the superbase client and then call the storage client on it just like we had the Au client we also have the storage client so to access Au you do superbase client. to access storage you do this and to access the database you can directly use from so anyways we have the storage and from Storage I want to go to a particular bucket and what is the bucket ID I created the bucket ID right if I go back to my SQL editor here I've passed in that my ID is blog images and in the storage also I can see blog images is over here so I'll pass in blog score images then directly call the upload method on it now if you have a binary file for example a u 8 list you'll be using the upload binary function I'm going to use the upload option because that will allow me to pass in the file directly so the file that I want to pass in is image let me get that right now what is the path the path it is asking me is not the path of this file the path it is asking me is where do I want to store this in this bucket well my path is pretty simple the name of the file should be blog. ID so I'll just pass in blog. ID like that and the reason I'm following this particular path is because my blogs cannot have more than one image so just in case something goes wrong and multiple images are there we are assured that there's only going to be one image per blog if you want to add the facility to add multiple images in the blog you can definitely make this path a little more detailed but for now I'm just going to put it as blog. ID so the name of my file is going to be blog. ID I'm also going to aade this and this isn't going to return anything useful to us so we can leave it over here now to get the URL of the image we'll have to do something like this return superbase client. storage Dot from then we're going to pass in blog uncore images then we'll again put dot and then call the get public URL function and in this function we need to pass in the path the path where my image is located is blog do ID and this way I'm able to upload my data to superbase storage and then retrieve the download URL and return it from this function one thing I forgot to mention is that if you have a more Advanced path you need to put slashes to separate the two things so if you do something like this blog. ID slash let's say images it's going to mean that the folder name is blog. ID and the name of the file is images so if you want you can do that however you need to make sure that if you change the path over here you change the path over here as well otherwise it's always going to return a wrong thing so now that we have completed this function two we're done with the data source for now so we can close everything and now go to The Domain layer to create an interface for our repository so in the domain layer I'm going to create a new folder let's call this repositories and in this I'm going to create a new file called blog repository. dot then here I'm going to Define my interface blog repository so it's going to be abstract interface class blog repository and inside of this I'm going to Define just one function and that's going to be future either failure and when we have a success what I want to return is a Blog so let me import that blog which comes from the entity then I want to import failures do Dot and then I want to import FP do do there we go after that I'll name my function so it's just going to be upload blog and as I said this upload blog is going to contain everything so using this function we're going to call the data sources two methods the upload blog image method and the upload block to database method so obviously we're going to ask for the entire user generated content here so we're going to require file image we're going to require string title then we also going to require the content then we are also going to require the poster ID that means the user who posted it and then we're also going to require a list of string of the topics so with this I have my interface created with one method upload blog and all of these parameters now if you're wondering why didn't I take a Blog model in the parameter that's because I'm going to create a blog model inside of blog repository implementation so all of this needs to be taken from the arguments now in the data layer I'm going to go ahead and create a new folder let's call this repositories and then I'm going to create a new file blog unor repository implementation do do then as we know it we just going to do class blog repository implementation implements the blog repository that that's coming from the domain layer then I'm going to implement the method so we have our upload blog function this function also needs to be a sync and I'm also going to format this so I'll put a comma here and there we go after that also make sure to remove this either do do file and import the correct fb. package after that the first thing I want to do is create a blog model based on all of these data so I'm going to create a blog model which is going to be a Blog model and then the ID is going to be randomly generated so we need to pass an ID over here now super base is not automatically going to create the ID we have to create it by ourselves and to do that I'll be using a package known as uu ID that's present on pub. so to install it we can do command shift p add dependency add uu ID this uu ID will help us generate a random ID based on the date or based on any other parameter we want I'm going to base it on my date so every ID that's generated is is going to be random so I'll just do constant uu ID so make sure to import The UU ID do. file and then you can run dot V1 V2 V3 whatever and then run V1 or V4 or V5 whatever you want I'm going to go ahead with V1 because it generates a Time based version uu ID so that's enough for me and there we go our ID is now done then the poster ID comes from the param meter title 2 content to now for the image URL part we don't have the image URL as of now so what I'm going to do is put in an empty string then we have topics and finally updated at updated at is going to be date time. now because this is the time we posting our blog right so datetime do now so we have a Blog model ready with us the next thing I want to do is contact the remote data sour source so that I can upload my image first of all to the superbase storage so here from The Constructor I'm going to get access to the remote data source so it's going to be blog remote data source let's call this blog remote data source and we're going to take that from the Constructor so we have blog repository implementation this blog remote data source now another thing I forgot to do is wrap all of this code in try and catch block because if I call some method from blog remote data source it's going to throw a server exception if any error occurs so I need to catch all of them over here so try catch block will be present then I'll take all of this code and push it in try block and if there is any error I'm just going to do return left failure and then I'll pass e do two string but if I go to my blog remote data source you'll see that I'm always throwing a server exception so instead of catching all the errors I can be specific that I only want to catch the server exception and this way I can pass an e do message instead of e.2 string now we have access to the remote data source so I can take the blog remote data source and call the upload blog image function first because this will give me a URL which I'll then assign into this blog model so I've passed in my image over here and my blog is going to be blog model then I can also avade this and this is going to give me the image URL so I can save it over here in this variable now I just need to update this blog model to include the image URL as this image URL to do this you might say we need to put this call above the blog model creation and you would be right but here's the problem we have blog model over here so if I try to put it above the blog model creation we won't have access to this blog model so I can't put it there what other thing can I do well I can just take this blog model and change its image URL property I'll take the image URL property and assign it to this variable however that's not possible because all of blog models fields are final if you see in the blog every single one of them is final and we saw earlier in the user class that if anything was Final and if you wanted to change the value we had to implement a copy with method so we can click on this bulb icon and generate a copy with function I can also remove this comment because I only need this function which I'm going to cut from here and put it inside of the blog model so I'll paste it over here and in instead of this being blog it's going to be blog model and we're going to return a Blog model as well simple now in the blog repository implementation I can do blog model is equal to blog model. copy with and then pass in the updated image URL which is this thing over here that's looking good now the only thing I have to do is upload this blog model to the superbase database so with this we uploaded the blog to superbase storage now we need to save this to the superbase database to do that we can do aait blog remote data source. upload Blog then we can pass in our blog model and this is going to return to me the most up to-date blog so I can store this in a variable called uploaded blog and then finally I can return right passing in the uploaded blog over here because that's what I want to return whenever my function is in a success mode blog so that's our entire implementation of the upload blog method now we just need to go to The Domain layer and create a use case for this so I'm going to close all the save files and in my domain layer create a new folder called use case or use cases and I'm going to create a new file for this let's call this upload unor blog. do and this is going to follow the same old process we are going to create a class upload blog which is going to implement the use case and then there are going to be two types over here the first is going to be success and then parameter the success is going to be the blog entity and the parameter we'll have to create that because there are too many parameters over here so let's create a parameter upload blog parms so whatever is the name of our use case followed by parms and then we can specify all the arguments so there's going to be final string poster ID final string title final string content final file which is coming from iio be sure about that don't make that mistake and then we have a list of string of topics the same things we took in parameter from the upload block function that we created in the repository class now I can generate a Constructor for this and then pass upload block params as the second type over here then I can create one missing override and this is going to be async and then I can Implement my own function now to implement my own function I'll have to get access to the blog repository class so make sure to pass that in blog repository like this and then take this from The Constructor so we have this Dot blog repository then I can just do return await blog repository dot upload blog and then I'll pass in all the parameters so I have params do image and I'll do this for every single one of them so I can just pass in parms before every argument and in the poster ID it's giving me an error because I think it's not defined I call this posted ID instead of poster ID so let me fix that over here and I think everything is fixed other than a semicolon there we go so our entire use case is now written as well the only thing I want to do is change the FP do. package so I know I'm rushing through this entire process but that's only because we've done this so many times now now I'm going to open my Explorer minimize all the folders using this button and then in the lip folder block folder I'm going to go to the presentation layer in the presentation layer I'm going to create a new block and that block is going to be blog block so let me name that and a new block is created with three files created I can close this use case and directly go to the blog State class so we have our blog State over here with blog initial so that's fine now let me introduce more States there's going to be a loading failure and success state so let me do that right away so I'll have final class blog loading which extends the blog State then we're going to have a final class blog failure which extends blog State then we have a final class blog success which extends blog State now whenever we have a failure we want to display an error so I'll also take that from the Constructor so we'll have blog failure this do error and if my upload blog is Success then I don't want to take anything from the Constructor because if it's a success what do I want to do with a Blog right what am I even going to display so I can go to the Explorer close this blog State create a new blog event and that's going to be called final class blog upload which is going to extend the blog event if you want to make this name better I would highly encourage you to do so because upload blog is a use case and blog upload is an event so you don't want to get confused between both of them now in the blog upload I do have many things to take from The Constructor so everything I mentioned in the blog parameter and upload blog use case I want all of that so I'll just copy this entire thing and paste it over here then I can take this blog upload class and put it over here also I need to import the iio package which I'll do finally I'll go in the blog block and here I'm going to remove all of these Imports and then fix it by importing flutter block again I'll go to block event and import the material. do file nice now just like before whenever we receive any blog event what I want to do is display a loading indicator first of all so that I don't have to emit loading state for every single event so I can just pass an emit blog loading whenever any event is caught after that I'm going to listen for another event which is going to be blog upload and then we're going to get our event and emit but for that I'm going to create a separate function down below so it's going to be void uncore on blog upload then I'm going to get access to the event which is of the type blog blog upload and then we have an emiter which is of the blog State and that is the emit function now I can take this function and put it over here now I want to take the upload blog use case from The Constructor so I'll have final upload blog upload blog and then I'll take this from The Constructor as well I'll also make this function asynchronous and then I can call the upload blog class in the upload blog class I'll pass in the upload blog parameters and then we need all of the things poster ID title content Etc which I'm going to get by using event. poster ID event. tile event. content event. image and event. topics after all of that is done I can just avade this and store this in a result variable then I want to resolve this result so I'll do result. fold and then whenever there's a failure I want to emit the blog failure State and then pass in the error message as l. message if it's a success then I just want to emit the blog success and that's not going to take any Constructor arguments so that's good for us and that's basically everything in the block for now next thing I have to do is register this block and even before registering this block I I have to register all the things I newly created in init dependencies do. file so just like I have a function for init o I'm going to have a function for init block so down over here I'm going to have voore init block and actually it shouldn't be in it block in it blog because I'm initializing the blog related dependencies then I can go at the top and call this function before I forget it now all of the initialization we're going to do is very similar to init o first we have to register our data source after that repository after that use case and after that block even if you change the order in which they are called for example if you call register lazy singl ton somewhere over here it won't cause an issue okay so you can do that but I like to follow that order because it gives me a good sense of what I've forgotten and what's left so I'm going to do service locator dot dot and the first thing I want to register is the data source so I'll have register Factory and then I'll pass in my blog remote data source implementation and then I'll pass in my super based client which is the service locator now when we register this factory make sure to put in the blog remote data source because this is of the type blog remote data source not blog remote data source implementation there can be error if we don't do that now let's register something else dot dot register Factory and this time we're going to register our repository so it's going to be blog repository implementation we'll pass in the service locator for the data source and we're going to register this as blog repository interface then I can register my use case which is the upload blog class and then I can again pass in service locator for the blog repository finally I have to register my block which is register lazy Singleton not registered Factory because we want to maintain the state that's kept inside of our block so I can pass in blog block and then pass in service locator for the upload block so this way we have registered everything now if you want you can put the comments again and I'm going to do exactly that so data source then we have the repository then we have our use case and finally our block that's looking good now I can close this init dependencies do. file go to the main. do file and then scroll up and create my own blog provider for the blog block so I can paste this block provider pass in the service locator but instead of putting Au block I'm going to put blog block then I'm going to save this file restart my entire application and nothing's going to change now and if you open the terminal there's no error either that's good now all I need to do is go to this add new Blog Page and call the particular event whenever this done button is clicked on and if you think about it this page has something like a form over here there's a title there's content the user has to select one topic and the user also has to select an image so it's kind of like a form right so let me add the form validation logic over here so at the top I'm going to create final form key which is going to be of the type Global key and we can pass in the form State over here just as we did in the authentication part now I can take this form key and attach it to the form that's going to wrap this entire column so the key property here can be the form key and then in the onpress I can do all the logic so here I can check if form key do current state DOT validate so if all the validation is true or not and for that validation to be true or not we have to set up the validation in our text form field which is created in the blog editor part so here we need to add our validation logic so I'll add validator then we get a value and then I'm going to check if value is empty so if the value is empty then I want to say return dollar hint text is missing just as we did before and obviously this value is never going to be empty now if the value is not empty then I want to return null that hey there's no error everything looks good if you want you can also do value. trim. is empty because space might take a character after that we can close the blog edit go on the top and continue with our validation logic so with this line we have validated these two text Fields now I need to check if at least one of the topic is selected or not if you want you can make this entire part optional but I want at least one topic to be selected so what I'm going to do is put and selected topics. length is greater than equal to 1 so if the length is greater than equal to 1 that means it is all right so the user has to select one topic and if you see the linter is giving me a warning that hey you can write this code more neatly so I'm going to replace this with is not empty and this looks good the next thing I want to check is if the image was present or not if the image is not present that's not going to work for us so I'm also going to check if the image is not equal to null so with all of these conditions I can be sure that all of the data is being passed now assuming everything is correct what I need to do is run context. read and here I'm going to pass in my block which is blog block then I'm going to add a new event over here and my new event is blog upload so I'll pass that in now I need to pass in everything poster ID title all of that so first thing we need is the poster ID and to access the poster ID I'll have to use the cubid that I created earlier app user cubid so if the user is on this screen we are sure that the user is logged in so I can take the user from here and get their ID so I can create a poster ID variable which is equal to context. read and I'm going to read the app user Cubit then I can access the state now this state can be anything but since we are on the add new blog page we know that this state is going to be the user logged in state so I can tell flutter to read this in a particular manner so I can wrap this entire thing with parenthesis and then say I need to treat this as app user logged in so this is the state that we are in the user is logged in and then I'll get access to the user property and then I can access the ID property using which I'll get the ID of the user now I can take this poster ID and pass it over here now to get the title I can do title controller. text. trim then the content is going to be content controller. text. trim then the image is going to be just the image and I'll also pass the bang operator because here we've already checked image is not equal to null so that means the image is not null and finally I'll pass in the selected topics over here and we are all set so this was a bit of complex logic to add in the UI part so I can take all of this and shift it in a function of its own so I'll copy all of this onpressed and create a new function let's call this void upload blog paste it in take this upload blog function and call it in the onpress of the icon button I think we're also missing a curly bracket over here so we'll quickly put that in the last thing I want to do is let the user know if it's a failure or a success if it's a failure I'll show a snack bar and if it's a success then I'll move them back to the block page so I'll wrap my entire single child scroll view with the widget of blog consumer and then I'll pass in the block as blog block after that I'm going to implement my listener so it's going to be if state is blog failure in that scenario I'll show a snack bar that says state do error I'm also going to check if it's a success so if the state is a success so blog success in that scenario I want to move away from add new Blog Page and go to the blog page Navigator do push and remove until we'll not be using push but instead push and remove until so that we never land on this page if we do push that means on top of this layer we are adding the block page but we don't want to do that we want to make sure that the user is not able to come back to this page back again until they click this button over here so I'll do push and remove until then I'll pass in the new route so I'll have to create that new route in the block page so let me go there then I can specify the static route fun function so it's going to be a material page route a builder is going to be present with context and then I'll pass in the blog page like this also this is going to be a constant now I can come back to the add new Blog Page and here mention blog page. route so a failure and a success state was implemented now what if we are in the loading state in that scenario in the Builder I'll just do if state is blog loading then I want to return a constant loader so I'll save this and we're done with the add new block page so I'm going to restart my entire app click on this button and let's say I just click on this enter you see it gives me an error saying block title is missing but the entire layout of my text field changes and that's because in my theme. do file I've not specified the theme of my input decoration theme when it is in error mode so we have enabled border we have focused border but we don't have error border so if it's an error Border in that scenario I want to display a border but this time it should be app pallet do error color so after I mention the error border and go back to my app and just hit enter you'll see block title is missing and the error border shows up but when the border is full focused you'll see our usual layout is gone it's not present over here so to fix that we'll have to pass in a border as well which is going to be just border then I can restart my entire application again go over here and let's say I hit enter the block title is missing I type something and a border is still present now so that's good now let's say I mention a valid title I'm going to say python for B beginners 20224 and this comes under programming then I'm also going to select a block content and let's say I just paste some gibberish so I'll paste my content here I'm also going to select technology so that I have two fields and then I'm going to select the image in my blog so let me select a nice image there we go now I'm going to click on enter and you see we have a loading state that looks good and we get shifted to the blog app we're not able to go back to that page until we click over here and then all of our details are gone from here so that means the blog upload should be successful so if I go to our superbase dashboard and go to my table blogs you see we have our ID that was randomly generated by uu ID updated at poster ID title content image URL and topics and you see topics is a text array now let's see if the image URL is correct so I'm going to take this entire URL and paste it in my browser and yep the image does load up another thing I want to check is if I go to the storage my blog image shows up successfully or not and there we go we have our image showing up correctly with the right mime type now you might want to compress this image when you upload this to the database and to do that you can simply go to the pick image function in the in the utility folder and here specify the image quality the image quality can be any value from 0 to 100 so you can decrease it from there so everything looks good over here now just to verify if the poster ID is correct I'm going to click on this view referencing record and it will open that profile in the super based dashboard and this is the user rager anav so that's good too now the final step is to display all of the blogs on this homepage so for that we'll have to implement our get all blogs function in the data source and then pass it down to repository create a use case call it in the block and finally displayed on the screen so let's get into that so let's go in the data layer the data sources folder the blog remote data source and here we're going to implement our method the method is going to be get all blocks so we are going to implement ment a method where we going to return a future list of blog model and this is going to be called get all blogs then I want to implement this method so I'll create one missing override and there we go now inside of this I'm going to first make this method asynchronous as usual we're going to have a try and catch block and then we're going to throw a server exception if we see any error and the message is going to be e.2 string after that in the tri block we need to get all the blocks so to get it all we need to do is call superbase client. from if we do from we have to pass in the table name and we want to get all the blogs from the block table so I can just pass in blogs and then I want to get some fields and what are the fields I want I want to get all the data that's present within the blog so I can just leave it empty over here but other than getting all the data that's present in the blog table so the ID updated at poster ID title content and image URL I need another field and that is the name of the user that's because when we display the blogs we want to display which user posted that blog and for that we'll have to get the latest information about our user what's the latest name of our user and to get that we know poster ID can help us do that because poster ID is a foreign key that is associated with the primary key of our profiles table so by using the poster ID I can get the name of my user and that's what I want to do now the question is how do I do it one thing I can do is get the data from the blogs table and then whatever data I get I'll take the ID and contact the profiles table to get this particular user data and by doing that I'll get the name of the user so we'll have to make two API calls now there's an easier way to do this how by performing a join operation on our SQL database it means that I'll get all of this data along with the data from the profiles table and we can do that because of this poster ID present over here because poster ID is a foreign key that will get us the user information of this particular row so to do that I'll go where in the select I have to pass in asterisk because I want to get all the data from my table so I'll get all the blogs and after that I'll put a comma and then pass in profiles then I'll pass in a parenthesis and pass in the data I want if I want all the data that's present inside of profiles I'll put asterisk but since I only want one column I'll pass in the name which is the profile's username so what this will do is get all the data from the blogs table and then it will go to the profiles table and get the name name of our user so we'll get all the blog data including the name of the user that posted this blog and again the only reason it works is because of this poster ID this poster ID is linked to another table so our superbase client knows where to go and find the particular user information so it will go to this particular user and get their name if we had passed asterisk it would give us the ID updated at and the name property all of them so this is the join operation that we can do in SQL and super base now I can just put a semicolon then store this data so we'll have final blogs is equal to a weit super based client now I have a list of map of string comma Dynamic but this time we can have multiple elements in our list we don't just want the first element in the list because there can be multiple blogs right now we only have one blog in our database SP but we can have multiple right and we want to display all of them so I need to Loop through this list and convert every single map into a Blog model so to do this you can run a for Loop or you can run a map function on the list so I'm just going to do blogs. map so we'll map over every single blog and let me call this Blog then I'm going to return blog model from Json function you see this is a reusable function then I have to pass in the map and the map is the blog that we get over here now after this map is done I'm also going to convert this to a list and then I'm finally going to return this entire thing because we need to return a list of blog models so we are looping through every single map in the list and converting it into a Blog model then converting it to a list and returning it from the function now here's a small issue if we go to the blog model we have the fields as I ID poster ID title content image URL topics updated at but there's no mention of the poster name the user that posted it because here we are also getting the name of the poster right there's no mention of that in our field so our blog model is not going to contain the name of the poster to fix that I can go to the blog entity and over here add a new field final string poster name then this poster name is also going to be nullable because when we create a blog model we not passing in a poster name right we only get a poster name when we are doing a join operation in get all blogs function so here I'm just going to do this dot poster name it's not a required field then I can save it go to the blog model then over here I can do super. poster name in two Json I'm not going to pass our poster name because in no situation do I want to store the poster name and in the fromjson function you might think of putting poster name over here and doing map poster name but we shouldn't be doing that that's because not every single time we call from Json are we doing a join function for example if I go back to our blog remote data source go to the upload blog function you see blog model. fromjson and here we don't have the poster name because because here when we're trying to get data from the blocks table we're just getting all the data from the block table we're not performing any join operation we're not joining the two tables together so if we add any field in the from Json it can give us an error and we do not want that so I'm not putting that in the from Json instead what I'm going to do is whenever I have a join operation created like this I'm going to use the copy with function over here so you convert the map app to a Blog model and then you can externally update the poster names but if you try to pass the poster name over here that's not possible because the copy withth function doesn't take that so let me update the copy withth function in blog model so we are going to get string poster name and then we're going to say poster name poster name this do poster name then we can close the blog model and over here we'll pass in the poster name as blog now what's the poster name going to be the poster name is not directly going to come from the map like this poster name it's actually going to be blog and then we getting the profiles table data so it will be in the profiles key and then we'll access the name property because in the profiles table the poster name is the name of the user so that's what we are getting and this will be it the reason I know this is going to be the value is because I had printed the blog data when I was creating My Demo application and that time I knew the data we are going to get from the blogs table will satisfy the condition that's present in fromjson and the data we get from the profiles table is going to be under the blog profiles key so when you're building your own application and you want to figure out how the map is going to look like just print it but anyways this is our entire logic now we can close our remote data source and go to The Domain layer to specify a new function in our repository and that's going to be get all blogs again with the type of future either failure list of blogs let's call the function get all blogs and that's pretty much it now I'll go in the data layer blog repository implementation and I'm going to implement this method so there we go now again we're going to have the same try catch block stuff so let me quickly create that so it's going to be async function then a try and a catch block then if there's an error we want to return left with failure pass to it and e.2 string and obviously I only need to catch the server exception so let me do on server exception and then e do message now in the tri block I want to get access to the blog remote data source and call the get all blocks function so I can do final blogs is equal to aait blog remote data source do get all blogs then I can return right and pass in the blogs from here because we are returning a list of blog model and this requires list of blog so with L of substitution that's done correctly now the next thing I want to do is create a use case for it so in the use case I'm going to create a new file let's call this getor allore blogs. then I'm going to create a new class get all blogs which is going to implement the use case then we need to pass in our success type so the success is going to be list of blog and let's import the blog from entity and then we are also going to have no params passed it because get all blogs doesn't require any parameter now let's implement the missing function there we go also this has to be async we need to take the repository from The Constructor all the same stuff that we had done before so we have get all blogs this do blog repository let's also remove either do and import the FP do do package then over here as usual I'm just going to do return await blog repository dot get all blogs then finally I need to call this in the block layer so let me go in the blog block then I'm going to import my use case so it's going to be final get all blogs get all blogs and I just realized we haven't made both of them private so let me make them private really quickly and fix everything in the Constructor so instead of requiring it manually I'm going to create a named Constructor then we're going to have required upload blog upload blog and we also going to require get all blogs get all blogs then after the colon I'm going to say underscore upload blog is equal to upload blog and underscore get all blogs is equal to get all blogs and that's all now just to remind you this is made private so that it's not accessible outside of the blog blog class now I just have to create an event handler and before doing that we need to create our own event so to get all blogs I'm going to create create a new event over here final class get all blogs which is going to extend the blog event and this is not going to take any parameter so that's cool now I can go back to blog block and add an event so we going to have on get all blogs and I think I've named the event incorrectly in blog event so let me fix that let me call this blog fetch all blogs or if if you want blog get all blogs both of them are fine then over here I'm going to listen to this event blog fetchall blogs and the reason I changed it to blog fetchall blogs is because the name of the event should be first so blog and then whatever you want so I'm just calling it block fetch all blocks after that I'm going to create my own function for this so it's going to be underscore on fetch all blocks Also let's fix all of these errors that are present over the reason these errors exist is because I changed the name it's not upload blog anymore it's underscore upload blog so after fixing that I'm going to implement this method so down I'm going to create a void function fetch all blogs and it's going to have the same parameters as this function or at least similar ones so I'm going to paste it and instead of blog upload it's going to be blog fetchall blogs and over here I just need to call the get all blocks function so let me put this as async and then I'm going to do final res which is response is equal to await uncore get all blogs and it doesn't require any parameter other than no patterns so that's done now I can resolve this response using response. fold and if it's a failure I want to emit blog fa failure and then I'll pass in L do message but what if it's a success do I want to emit block success like this well here's the problem block success does not take any parameters block success does not take any Constructor arguments and because of that you cannot pass R over here to fix it maybe you can say that I'll go here and I have final list of blog and then I'll have blogs taken from the Constructor so we have blog access this do blogs and this would probably change things I can go back to blog block and pass in my R but I still have another error and it's over here in on blog upload method I'll have to pass a list of blogs here too so maybe you'll say to resolve the error I can just put a constant list and that should be fine but it's not think about it let's say in the beginning when I restart my app all the blogs are fetched and displayed on this screen after that I go over here and upload a new block so once I upload click on this and it's a success it's going to emit block success and it's going to change the list of blogs from all the blogs that we fetched from database to this constant empty list if it's changed to an empty list and we come back to the screen our screen would be empty we would see no blog and that's not what we want so to fix this what I can do is instead of having just one success event I'll have two success event one for upload success and one for display success so I'm going to call this class blogs display success and put it over here I'm also going to create a new class which replicates our old class which is blog upload success which extends blog state so this way whenever I upload it's going to have this state and whenever the display play success I have this state two different states so it won't interfere with my application now I can pass in the blog upload success over here and here I can pass in blogs display success now all our errors are gone from this file let's fix other things that we might have so in Explorer first thing we need to do is go to add new page and instead of checking if the stat is blog success I'll check if it's blog upload success and if it's an upload success then I want to go back to our blog page now I'll again go to Explorer and in the inet dependencies I have a few things to fix so I'll go down and now here instead of having positional arguments we have named arguments so I'll pass an upload blog over here so the upload blog is service locator and to pass in get all blocks first I need to register it so I'll register a use case so I'll do do do register Factory pass in my new blog pass in my new use case which is get all blogs then I'll pass in a service locator again as I need to pass in blog repository and then I'll pass in my service locator for the get all blocks that's all now I can close this in dependencies do file go to our Blog Page and here I want to call the function to get all blogs and display them on the screen now I need to do that as soon as the app starts right so as soon as I restart my app and this Blog Page shows up I want all of the blogs to be listed so it only makes sense for me to do this in the init State function so I'm going to refactor this and convert it into a stateful widget and after that I can access my blog Block in the init State function so here I'm going to do context do read then I'm going to talk to my blog block and then add an event of blog fetch all blogs and this way hopefully we will be getting our blogs now I need to display the list of blogs to do that I'll minimize this actions part and in the body of the scaffold we want a list view Builder because we are going to get a list of blogs that we want display on the screen so we'll use a list view builder then pass in an item Builder where we are going to get a context index and then we're also going to get an item count now to get the list we'll have to wrap our entire list view Builder with a block consumer widget so let me do control shift R and I'll wrap all of this with block consumer then I can pass in blog block and block State then then here I can check if the state is blog failure that means something unexpected happened and that case I want to show a snack bar saying that hey an error occurred so it's going to be state do error now if we are in the loading State what we want to do is check if state is blog loading and you might say that hey we've not emitted the blog loading state in a blog block right but we have you see we had our catch all event where we directly begin the loading state so we don't have to worry about emitting blog loading every single event so we can have a loading State and we will have that so let's return a constant loader in that scenario now if the state is blog display success and that scenario I want to return a list view Builder and if it's none of them then I just want to return a size box so I'll have return size box like this now in the list view Builder I need to mention the item count so the item count is going to be state DOT and you see we get a list of blogs over here so I can take this blogs dot length in the item Builder we want to return our own block card that we'll manually create but for now I can just do return text and I want to return the title just to make sure everything's coming out properly so I can extract the blog from state. blogs doing this final blog is equal to state. blogs and then pass in the index to get one blog after that I can take this blog and call the title property on it then I can save it I'll restart the entire thing and you see we get our first block python for beginners 2024 showing up so that means our entire process is a success and this part particular thing will work in all scenarios because we've created two states if we had created one state I've already told what the problem was going to be if it was blog success for upload and display that would mean that it displays a list of blog over here when I go to the new screen upload the blog it will again have a Blog display success with an empty list so when I come back on the screen it's not going to show anything even though it's a success because using this state I'm getting the item count and the item count would be zero so nothing is going to get built so I hope that was understandable the next thing I want to do is create a fancy block card which will be displayed over here instead of this text called python for beginners 2024 so let's get into it right now instead of writing the cards code over here I'm going to write it in the widgets folder that I created so here I'm going to create a new widget called blog _ card dot dot then it's going to be a stateless widget and let's call this blog card then here I'm going to return a container with the height of 200 and a child where I'll display the blog's title just to see if it's working out properly so I'm going to take the blog entity from The Constructor of this card so I'll have blog. tile being displayed over here okay now now I'm going to go to the blog page and return the blog card from here I'll also pass in the blog model that I extracted over here then I can save it restart the entire app and I still see this python for beginners because I'm not added any color to this container so let me see if it takes the height of 200 so in the decoration I'll pass in the Box decoration which is going to have a color and the color if you see is different for every single card now if you want you can change the colors over here I've just put the color as the gradient of my button you might want to change this to Red Green something like that and I'll show you how that design is going to look like so my point is that there's different color for every card just like there's different text and different topics for every card so it only makes sense for me to take that from the Constructor as well so I'm going to have final color color and I'll require this color from The Constructor to Let's also go to the blog page and pass in the color for now let's say all the blogs are of the same color which which is app pallet. gradient 1 now of course we are going to implement our logic so that our blog cards have different colors but for now it's the constant now I can go back to our blog card and specify the color over here now let's see a python for beginners should shows up that's nice and the card is taking pretty much the same space so that's nice the next thing I want to do is add some spacing from the side leave some margin so here I'm going to pass in the margin not padding because if I add in padding it's going to leave some space from the inside margin is going to be the outside thing so make sure to add margin we also going to add padding but padding is going to deal with the stuff that's inner margin is going to deal with the stuff that's out of the container so the margin is going to be ENT sets. all and we'll pass in 16 let's put a cons to that now if I come back this looks solid now I just want to make this rounded over here so to do that I can go in the decoration and specify the Border radius of this container so it's going to be border radius do circular and we'll pass in 10 then I can come back and everything's rounded that's looking good next thing I want to do is leave some padding from here the text is shifted right in the corners I want some padding to be present so I'll pass in padding as constant Ed and sets. all 16 again then I'll come back and this is looking good the next thing I want is three elements that are laid out vertically these set of cards this text and this blog reading time so obviously for this we'll have to wrap our text with a column widget so that everything's laid down vertically after that I'll have to lay out my chips over here so to do that I'm just going to copy the same code that I had in the add new blog page so I'll scroll down and I have this particular thing I need to grab this entire single child scroll View and paste it in the blog card so I'll have this done now now instead of having all of these conditions in the side we don't want the side at all I want it to be null because the Border should appear over here the same goes for this color so I'm going to leave it out as well I'm also going to remove the gesture detector from the chip because we do not need that so I'll click on remove this widget and I think this is looking good so we have our chips over here that's nice but instead of displaying all of the chips I only want to display the chip that I had selected so that means I need to access the blogs topics and display them so instead of passing this list I'm going to have blog. toopics do map and then we have only two chips displaying programming and Technology that's right but if you see these two chips are right in the center I want it to go to the beginning of the access to do that I can go to the column and say the columns cross axis alignment should be cross axis alignment. start it's cross axis alignment because the main axis alignment of a column is vertical the cross axis is going to be horizontal so if I do that the chips go in the beginning and that's right after that I need to work on this text this text should be much bigger and Bolder so I'm going to have the blog title as style text style and I'll pass in the font size as 22 and the font weight as font we. bold I'm also going to put this Tex style as constant there we go so after this the next thing I want to focus on is this reading time this reading time should be displayed over here and to do that I can just put a text let's say 1 minute for now we are going to dynamically calculate this in just a minute but let's get the layout right so we have constant text 1 minute and it's displaying over here now I need to leave some space between between these two things to do that I can just do constant size box height let's say 100 but that's too far let's do it 70 that's still too far so let's do 50 and that's right but here's the problem what if the text is not python for beginners 2024 instead it's going to be something that's taking two lines so it's going to have a text over here a text over here as well so that means 1 minute is going to again have a render flow error so it's not a dynamic layout and can fall short in certain scenarios we don't want that so to shift this to the bottom I can go to the column and pass in the main access alignment as main AIS alignment do space between with this if I go back to my card we have 1 minute displaying over here in the bottom but rest of my layout is destroyed that's because we are leaving space between these two elements and these two elements we don't want that we only want space to be left between this and this so to make this work what I can do is treat both of these elements as if they were the same thing so I can treat these two wigets as one viget and I'll treat this as another and then I'll have my column as space between so there would be space between this one wiget and this one widget to do this I'm going to wrap my single child scroll view with a column and I'm also going to wrap my text with within this column and then our layout is fixed but again we have the same problem our chips over here are again in the center to fix that we'll have to take this cross axis alignment and paste it over here as well make sure to not remove this because then our 1 minute text is going to come in the center we don't want that so in both the cases our cross axis alignment is going to be in the start we'll restart and we see the same thing now the next thing I want to do is calculate the reading time dynamically and to do that we'll have to implement a small algorithm and I'm not going to implement that algorithm over here in the blog card you can do it if you want but I know that this algorithm can be used in multiple Parts because when I click on this and go to the blog viewer page we also going to have the same minutes displaying so instead of strictly implementing the function and algorithm over here in blog card I'm going to write this in the utility function so I can go to the Explorer in the core folder we have utils and here I'm going to create my new util called calculate uncore reading time. do now this calculate reading time function is going to return an integer and then we can name the function calculate reading time and create a function function out of this now what's the algorithm of this calculate reading time function well first of all I need to get access to all of the blogs content based on the blocks content I'm going to determine how many words are there and then determine the time it will take for a user to read this so I'll accept the content from the parameter after that I want to know how many words are present in this content now how are words present in a sent sentence think about it if we have a sentence like ran is a good boy how many words are there how do I know how many words are there ran is a word is is a word a is a word good is a word and boy is a word I know this because we have spaces in between word is a string that is separated by spaces or full stops or new line characters but this full stop part is not right because if we have ran is a good boy.com that's one word so boy.com is going to be treated as one single word so we can count a word just based on the spaces and new line characters by new line character I mean if a new sentence is written over here this is also a new word right and in terms of string it is going to be displayed as something like this so we need to keep track of this slash in and the space to figure out how many words are going to be there now to do that you can Implement your own custom logic using a while loop and a for Loop but I have a simpler way I can just use a regular expression to do so to write regular expressions in flutter or dot you can just do reg expression like this then you need to Define your pattern so I'll pass an R followed by my pattern so my pattern is back slash S S Plus so with this I'll be able to split the text by spaces and new line characters to count all the words so this is the regular expression but I want this content to give me a list so I can pass in content do split so in this split function you can specify your own pattern so it can be a string like this so that would mean you need to split all the words by a comma but what I need to do is split all the words by this regular expression that will let me know if it's a space or a new line character and this will return to me a list now I need to calculate the length of this list to know how many words are there and I can save this in a variable so we are going to have final word count equal to this now I'm going to use the speed is equal to distance Upon Time formula to calculate the time it would take to read these many words so I have the dist the word count is the distance I need to calculate the time so obviously I need the speed now what is the speed of reading if you Google you'll find that humans have an average reading speed between 200 to 300 wordss per minute so maybe I can take the reading speed as 225 or if you want to take the lower limit you can take 200 or the higher or upper limit 300 but I'm going to take 225 and then I'm going to calculate my reading times so it's going to be final reading time is equal to the speed which is 225 divided by the distance which is the word count and this way I'll have the reading time now I just need to return this reading time which is going to be a double and it's a double because if you have 225 divided by let's say 100 words it's going to give me a double value for example 2.25 and I don't want to return a double from this function I want to return an integer so to fix this I can return reading time dot two integer but if I do two integer it will sometimes take the lower value or sometimes take the higher value I always want to take the higher value and that's why I'm going to do Seal Seal means it will take the highest number possible by rounding it off so if you have 2.25 it's going to take 3 minutes so that's my entire algorithm I can remove this so this function is now completed I can go back to my blog card and call this function to dynamically calculate the number of minutes so we are going to have calculate and obviously for that I'll have to do string interpolation then I'll call calculate reading time and pass in the content the content is going to be blog do content if you want to add the text as well you can do that but I'm just fine with block content then I'll remove this constant because a function is called and that's all now you see it saves 3 minutes and if I add another blog and let's say the title is how to get rich and the content is I want to get rich this is way less than 225 words per minute and also let's select an image and then we can press enter so new blog is uploaded and now we have python for beginners 2024 how to get rich and how to get rich says it's 45 minutes and I think that's because we have implemented the algorithm incorrectly it should be word count divided by 225 not the other way around time is equal to distance upon speed so it would tell me how many minutes it would take for me to read this blog on average now I can restart the app and you see both of them says 1 minute now let's try to get Beyond 1 minute so I'm quickly going to select an image this time we have technology and business how to grow a startup and let's find some content my content is going to be to return this entire container text just for the fun of it and then I can hit enter now a new blog is uploaded we have how to grow a startup over here it's still 1 minute I think we made a mistake let me do this again and this time I'm going to paste this many times just so that I'm sure we get something that's beyond 1 minute and if I scroll down I see something that's 4 minutes so that's good so yeah it calculates dynamically and everything seems to be done other than the color part so let's fix this color part we want to display different color for different blog and it depends on the position if you see if it's the zeroth blog we want this color if it's the first blog this the the second blog this then if it's the third blog again we want to repeat this entire scheme so again we'll have this color this color and this color to implement that logic I'll have to close all the save files and go to the blog page where this blog card color is given here I'm going to say if index percent 3 is equal to zero that means we either on the zeroth blog or the third blog or the sixth blog in that scenario I want to put gradient one otherwise I want to check if it's index percent 3 equal to 1 that means I'm on the first Blog the fourth Blog the seventh blog or the 10th blog in that scenario I want to put app pallet. gradient 2 and finally if it's none of these then I'll just pass in app pallet. gradient 3 so you see this is my entire condition and now we we have something that looks very similar to this one the zero block is this second is this third is this there's another small thing I want to change and that is the spacing that's there between the two blocks you see the spacing between them is too much and that's there because if I go back to my block card you'll see the margin is 16 from all the sides so that means there's a margin from here here here and here which is 16 I want to reduce the spacing between these two blocks so to do that I'm going to set this margin to 16 from all the sides except so I'll do copy with bottom and let's put bottom as four and with that we have our design properly replicated this app design was inspired by the dribble design I found online and that is created by YF so I've mentioned the link in the description if you want to go and check him out please do so he's used the colors red green yellow and this bluish color so if you want you can replicate this design by using these colors and I think the app will look much better I just try to follow it with the theme I had in my application anyways this color is putting me off so what I'm going to do is go to the block page and remove this part and just have two colors if index percent two is equal to zero then I want gradient one otherwise gradient 2 and this way my app will look much better yeah the last thing I want from this application is whenever I click on this I go to a new page where I see the image and the content along with the name of the user who published this and the date it was published at so let's get into that so that should be fairly easy for us I'm going to close all the save files go to the Explorer and in the pages I'm going to create a new page called blog uncore viewer page. do then I'm going to call this a stateless widget because there's actually no state that we need to maintain in it and then we can do blog viewer page let's name this properly after that I'm going to return a scaffold here there's going to be an app bar just because I want a back button to be present so when the user clicks on it they go to a new page and have a back button on the app bar that's why the app bar is present I can also Implement a static route function so we are going to have a material page route where the Builder is going to be present and we going to return blog viewer page we'll also put this as constant and then go to the Explorer block card and then wrap this container widget with a gesture detector widget so let's have that and in the on T we're going to do Navigator do push context and we're going to specify the route as blog viewer page. route then we can save it we'll restart the entire application and let's see if we go to a blank page and there we go we also have our back button using which we can go back awesome the next thing I want to do is display the title display the name of the user the date it was published at followed by the image and the content of the blog so this is what it's going to look like the first thing we need is a column inside of which I want a title so I'm going to have a body column then in the children we going to have a text that's going to be the blog's title so even over here we are going to need the blog from The Constructor so let's take the blog from The Constructor so we have required this do blog even over here here we're going to have the blog accepted from the function parameter and pass the blog like this this is not going to be a constant anymore so let's remove it and that's looking good now I can pass the text as blog. title and now we should be able to display something but we're not that's cuz we have an error in the blog card we need to pass in the blog over here in the route so I'm going to pass that in and this blog is coming from our Constructor so we can do that now I can close this and you see we are getting an error saying null and that's because earlier we had not passed the blog from this route parameters so let's restart the entire app and it should work there we go now I just need to bold this and increase the font size so I'll pass in the style as Tex style where the font size is 24 and the font weight is font weight. bold we can also put this textile as constant awesome now you see that a text is stuck on the side I want to put some padding or margin so you can wrap this column with padding or margin whatever you want I'm going to wrap this with padding and it's going to be 16 now I want to leave some space after which I can pass the name of the author so I'll have constant size box height 20 and the text is going to be buy and here we're going to specify the name of the poster so we'll have to use string interpolation we'll have blog. poster name and hopefully we do get a poster name so let me save this and we have the correct poster name showing up so our SQL join ran nicely now I just need to style this text so I'll pass in style as textile the font weight is going to be font weight. w500 not too bold but Bolder than my normal font weight and then the font size is going to be 16 Also let's put this as constant so I have the author name also showing up I need to move this to the left hand side to do that I'll specify the columns cross axis alignment as cross access alignment. start nice after that again I'm going to leave some height and specify the date it was published at followed by the number of minutes it will take to read this blog so I'll pass in a text that says first the date so to get the date I'll do blog. updated at then I'll put a full stop after which I can call the calculate reading time function again which comes from the utils folder and I'll specify the block content which is blog. content then I can save this and I see the date followed by one I also need to specify minute over here and yep there we go let me leave some height over here so we'll have constant size box height of five this time because the space left over here is smaller than the space left over here I also need to increase the font size of this text and change it to gray color to do that I'm going to specify the style which is textile the color is app pallet. gr color and the font size is 16 I'm also going to put this as const nice I also need to bold this a little bit so I'm going to copy this same font weight and paste it over here the date over here looks quite different from the date over here and we are going to format this in just a minute but let me put put other things over here the image and the blocks content so in my code again I'm going to leave some height and this is going to be a height of 20 because we leaving a space between these two things it's going to be much bigger so we have clip our rec with border radius as border radius do circular 10 so that we leave a nice enough border radius and then a child as image. Network image URL we get it from blog. image URL so let's save it and we have our image showing up over here that's nice if you want to set some constraints on the image over here you can do so by wrapping this widget with a container but I'm not going to do that because I want the image to be as long as the user specified after that again I'm going to leave some height and finally we are going to have the text of blog. content so let me paste that and here it is I will increase the font size over here so let me have a style with text style passed to it where the font size is 16 and if I come back the font size is looking bigger that's nice but we have an error bottom overflowed by 72 pixels to fix that we'll have to go right at the top and wrap my padding widget with a single child scroll view so that the entire thing is scrollable and the person can read properly if you look closely another thing you'll realize is that the line spacing between these things is a lot here the line spacing is not as much so to increase the line spacing that means the spacing left between the lines we can scroll down and change the height over here to two then I can also put a constant save it and this looks better the height is generally increased between the lines because it becomes more readable for the user the last thing we want to do here is format this date now to format the date we going to be using a package from pub dodev called Intel as you can see it was published two months ago and it was done by the dot team themselves so it's a good package to use I'm going to copy this and add it to my application Now intel provides internationalization and localization facilities including message translation plurals and genders date or number formatting passsing and BYOD directional text all we need is the date formatting part so we're going to utilize that now this date formatting can be required by multiple features in our app not just blog viewer page so I'm going to create that in the util folder as well so in the util I'm going to create a new function called formator date do dot here we are going to have all the functions of formatting the date as is going to to return a string and it's going to be called format date but I'm also going to specify extra information over here I'm formatting the date by D mmm y y y y so this stands for date month year so I want the date to be present followed by the month in three letter characters and then the year which can be four character so D mmm y y y y y then over here I'm going to take the date time as the parameter and then I'm going to return date format and here specify how I want to format my date so here I can specify D mmm comma y y y y y then I can call the format function that's present on date format and specify my date time and this way I'll get a string that is totally formatted if you want more knowledge on how to format this thing you can read the documentation present in Intel here you'll see we have date formatting and passing using which you can understand how to format your date the way you want it to show up so I'm happy with this I'll go to the blog viewer page and instead of just doing blog. updated at I'm going to cut this and instead say format date by this this this and then specify my date time which is blog. updated at after that I'll come back over here and I see first March 2024 1 minute and that is the time that I publish this blog so that's good if I go to another blog that I published today we have 2nd March 2024 4 minutes showing up and everything looks good it is scrollable but one problem I have with this is when I scroll it doesn't tell me how far I am I would like a scroll bar over here which would let me know where I am and if I want to scroll quickly I can do that so in the blog View your page I'm going to wrap my single child scroll view with a widget known as scroll bar so this scroll bar will provide me with an external scroll bar as you can see and then I can scroll my stuff really quickly and it also lets me know where I am in the blog reading process so you might think we are done with the application but no we're not we are forgetting one essential feature let's go back to our flowchart and see what we have completed so we start we've completed all of these things then is the user authenticated here we have a logic is internet connection present if the internet connection is present we're fetching blocks from super base and we're doing that on the homepage but what if the internet connection is not present then we want to display blocks from local storage and that is the logic we've not implemented and if we go to see we've not even implemented the logic of is internet connection present because we are just assuming that the internet connection is going to be present now how do I check if the internet connection is present to do that we have a package internet connection Checker plus if you want you can go ahead and use any other package you know of for example Network info and that should help you as well but we're going to be using this plugin so I'm going to copy this add it to my pope. yaml I can close all the save files and in the core folder I'm going to write this connection Checker logic that's because this connection Checker class that I'm going to create is reusable across multiple features even in the Au feature even in the blog feature in almost every feature we'll have to check if the connection is present so here I'm going to create a new folder let's call it Network and in that I'm going to have a new file called connection Checker do Dot and first of all I'm going to create an interface so that our entire code is dependent on interface instead of concrete classes so I'll have a interface called connection Checker and in that for now we are only going to have one getter and that is going to be of the type future Boolean get is connected so this will let us know if the device is connected to the network or not then we're going to create an implementation of this class so we are going to have connection Checker implementation which implements connection Checker then we're going to create one missing override it's going to be a synchronous and then I'll be using the internet connection Checker plus plug-in to return a value if it's connected to the internet or not so let me import that from the Constructor again so we have final internet connection internet connection and then I'll create a Constructor so we have this do interet connection then I'll check internet connection dot has internet access and I also need to Avid this so if the internet connection has internet access or not if it has internet access then it means that it is connected otherwise it doesn't if you want to make this more extreme you can do that this will just let us know if at one point our app has internet connection or not if the internet connection status changes it's not going to let us know so if you want you can go ahead and use the stream part of this plug-in and that will let you know if the internet is connected or disconnected at any point so you can basically listen for internet connectivity changes but I'm fine with this the next thing I'm going to do is go to the authentication part in the data layer repository I'm going to implement my logic none of the other things have to get bothered only the Au repository implementation is going to change and that is the benefit of using clean architecture and writing code in layers I only have to bother one file and one class instead of doing it in every single place because data sources only contain superbase related logic so I'm not going to put it there Repository is where I have to put all the network related task and call various things from auor remote data source so I'm going to close this Explorer and write my logic now now where should I write my logic should it be in the signup user login user or current user and the answer is it should be everywhere so I'm going to first take the connection Checker from The Constructor so connection Checker comes in and then we have this do connection Checker then in the Lo login user and signup user we are returning get user function right because that was a reusable function if you remember now what I'm going to do is go to the get user function and here just check if the connection is present or not if the connection isn't then I want to return a failure saying that hey there's no connection so here I'm going to check if connection Checker dot is connected is true or not and since this is of the type future Boolean I'm going to await this entire thing and then check if it is connected if it is connected then I want to run all of this but if it's not connected so I'll put an exclamation mark here then I want to return left with failure saying no internet connection now let's see if this logic even works so what I'm going to do is restart my entire application right now we have internet connection so let the internet connection go away I'll again restart the entire app and it's not restarting properly and that's because there's an error in the lip folder and it's there because in the inner dependencies we have added a new dependency but not registered it in the service locator so let me register it so I have my core comment over here I'm going to register the service locator and this has to be a factory because whenever I call a new connection Checker I want to check if the connection is present or not so new instance has to be created every single time so I'll pass in the connection Checker implementation then I'll also pass in the internet connection object and for that also I'll have to create a separate service locator so let me do that service locator. register Factory then I'll pass in the internet connection then I'll take the service locator pass it over here so I'm returning connection Checker implementation and as you already know instead of passing in the register Factory as connection Checker implementation we're going to do connection Checker the interface now I can go down and pass in the service locator for the second argument as well now I can restart my entire app and when there's no internet connection we get this error message and we'll understand why we get that error message but when I click on sign in first of all we get the form validation error let me fix that then I click on sign in and it says no internet connection so this seems to be working and if I do the same thing in sign up it's going to work because it's the same function the same reusable function that's being called ultimately now if I restart my entire app again you see we get this error client exception with socket exception and we get that error because we're trying to call current user function and in the current user function we have not specified what to do if there's no internet connection so let's implement the same logic over here so I'm going to have if so if the internet connection is not present for the user in that scenario I do not want to put out an error message saying that there's no internet connection no if the internet connection is not present I want to log the user in if they were logged in when the internet connection was present so basically I want to do all of this stuff but offline not all of it at least some of it so if we go to our Au data source here you see we have created a getter and that is the session part this session is not future that means it can be accessed offline so I'll take help of this session to know if the user is logged in or not and if the user is logged in I'm going to return the user model based on the user that's present in the session class and if the user was not logged in then we're not going to return anything we'll return a failure saying user is not logged in so I can use the session variable that's present in the author remote data source so I'll have remote data source do current user session and I'm going to store that in a variable so I'm going to have final session is equal to this now if session was equal to null in that case I want to return left saying user is not logged in but if the session is not null I want to return a user model with users details in it so I'm going to return right with user model passed to it the ID is going to be session. user doid the email is going to be session. user. email but we won't have access to the name of the user so it can be empty for now and probably there's no way to get the name of the user either so we can just store it as an empty string anyways the name is not going to matter it only matters that we' have returned a user model with the user ID mentioned in it now if the email is not present which is highly unlikely we can just return an empty string too so we can save this so if I restart my entire app the user is now logged in if the user was not logged in then we would still see the sign up and login page now the next thing I want to do is display the blogs that the user can see so if I go back to my flowchart you'll see that we checking is the internet connection present if yes fetch blocks from superbase if no we want to display blocks from local storage now you might ask first of all how do I access this local storage to access this local storage you can use multiple plugins that are present on pub. deev shared preferences flutter Secure Storage Hive iser sqf light anything you want but I prefer using Hive because it's pretty easy to use and it will help me store a bunch of data in the database if you want to use sqf light that's a good choice too isar is a good choice too but if you're planning to use shared preferences or flutter Secure Storage that's not a good option because shared preferences and flutter Secure Storage are used to store data that are small not entire blogs so if you want to store the JWT of the user or some small data of the user you can store it in shared prefer ref es or flutter Secure Storage but if you want to store large data you can store it in Hive now the next question is how do I display blocks from local storage the local storage is going to be empty right and that's the thing if it's empty how are we going to display blocks so to do that we can do one thing whenever the internet connection is present we're going to fetch blocks from superbase store it in local storage and whenever the internet connection goes out we can display those blogs from the local storage and that's what caching is so we are basically caching our blogs in the hive database so basically let's say this is our Hive database I'll fetch the blocks from superbase when the internet connection is there I'll store it to Hive then whenever the internet connection goes out I can access the latest blogs that was stored in the hive database so on Pub dodev you can go ahead and find the hive package you can see it was published 20 months ago so you might think that's not a good choice but if you go to the pre-release it was published just 6 months ago so we can use this pretty release version and if you know a little something about Hive you might know that the guy who built iser also built Hive so you can use the isar database that's what he recommends or you can use Hive I'm going to use Hive so let's go ahead and copy this then go to the pope.l file and paste that in the dependencies now there are more things we need to add in the dependency for example either flutter Libs and path provider so let's add that too so we can copy these things and paste it over here so after flutter up get is run successfully what I can do is close all the folders go to the lip folder features block folder data data sources and instead of having just a remote database we are also going to have a local database so coming back to this diagram over here you see we had a remote data source now I have the local data source and in this local data source I'm going to use Hy so let's create a blog local data source do. file after that we can create an abstract interface so we have blog local data source and in that we going to have two functions first we going to have upload local blogs and here we're going to require a list of blogs we're not just going to require one blog so that we can upload it no we're going to require all the blogs that the user can see and upload it to the storage so we have blogs like this and also let's import the blog model the next function we're going to have is to load all the blogs so we're going to return a list of blog model which is going to be called load blogs and you see none of them is a future and that because Hive Works offline obviously it has to after that I can create a concrete class implementation of blog local data source called blog local data source implementation which implements blog local data source after that we need to create two missing overrides load blogs and upload logal blogs so first I'm going to create an implementation of upload local blogs so in this we'll be using Hive so I need to inject that dependency and take it from The Constructor so I'll have final box that's how you use Hive you'll have to create a box and then pass this box through the Constructor so we're going to have a box then blog local data source implementation Constructor and then we'll take this box then I can use this box to upload data to the database so I'll have box Dot and you see we have a bunch of methods over here like add add all clear close delete whatever I want to do but if you read The Hive documentation it says that when you have a bunch of blocks to upload to your local storage make sure to use WR because this is going to create a transaction and transactions are a good way to efficiently write your information to the local storage so whenever you have a bunch of data to upload to Hive you always use WR it will efficiently insert or update multiple values in the database so I'm going to make this function a block function and then I'm going to write my logic so to upload my block to the local storage all I have to do is box dop put and then we need to specify the key and the value the value is going to be one blog right we not going to store the list of blogs directly inside of one key so what I'm going to do is run a for Loop and put all of that data one by one so I'm going to have for in I is equal to 0 I is less than blogs. length I ++ a standard for Loop then I can pass my box. put function in it the key is going to be I do2 String because this accepts a key of string so whatever index the blog is I wanted to put that as the key and the value is going to be blogs at I and that is the entire function but think about it right now we have the internet connection so let's say we fetch all the blogs and upload the blogs to database so our database consists of all these blogs then again I restart my app I have all of these blogs and all of these blogs will again be stored to the database in addition to the blogs that I stored earlier so I'll have a repeat set of blogs I do not want that so what I'm going to do is clear off my box data before I upload any other data so I'll call the box. Clear method so this will remove all the data from my box and after that I can start writing my data to the local storage so let's assume that works for now and since we are here let's also write the implementation of this function load blocks so to get all the blocks from hive database we can use box doget and then specify the data we want want so to get the data we have to put the key so my key is 0 1 2 3 4 how am I going to get that to get that I'll again have to run a for Loop so I'll run a for loop from zero but not till blogs. length because now I don't have access to blogs I'll run it till box. length so box. length is going to be the number of entries or number of values that are present inside of the box and then I can specify box doget I do2 string and since we are getting too many things we can again create a transaction like we did over here box. WR instead of doing box. right I can do box. read then specify all of this in the in the function definition but I'm still not returning a list of blog model so to return a list of blog model first I'll have to create a list like this which is initially empty and and let's call this blogs then I can add to this blogs this data so I'll have blogs do add box. getet I do2 String but this is not enough and this will give us an error later on because box doget is going to give me a Json and actually I've not specified two Json over here as the value so let me do that so in the Box I'm uploading two Json value so I'm going to upload a Blog in my local storage and when I get it I'm going to get a map which I'm adding to a list that contains blog model so I need to convert this Json to a Blog model so let me do that really quickly blog model. fromjson and then pass in box doget I do2 string and that's all I need now I can just return the list of blogs and we're done with the entire code so I hope you understood this just to give you a summary we are uploading local blogs first we removing all the existing data in our box so that we can start fresh then we writing all the blogs that the user has seen to our database and we're storing that in a Json or a map format then when we load the blogs when the internet connection is not present we convert that map that we get into a Blog model and add it to a list which we are later returning that's all now I can go back to my repository and here import two dependencies my first dependency is going to be blog local data source which is blog local data source like this and I'll also have an internet connection Checker so I have connection Checker connection Checker and I'll take all these three things from the parameter so I have this do blog local data source this do connection Checker and then while uploading the blog I don't don't want to upload anything to the local storage because whenever I upload a Blog it shouldn't be uploaded to my local storage when I get some data from the superbase database that's when I want to upload my data to local storage so I can just have a simple if condition over here saying that if not await connection Checker dot is connected so that means if the user is not connected to internet connection then I want to return a left saying no internet connection that's all I need in the upload block function now I'll go to the get all blocks function and over here we going to have our logic so again I'm going to check for the same condition so I can copy all of this paste it if the connection Checker is not connected to the internet then I don't want to return a failure directly I want to fetch data from my database and that is the local data source so I can just do final blogs is equal to local data source dot load blogs so I have a list of blog models with me then I can return right and pass in the blogs so if the user is not connected to Internet we load the blogs from the local storage and return that and it satisfies a condition because we need to return a list of blogs but right now if you think about it there's no data in our database and we want to upload that data to our database whenever the internet connection is there so right now there's internet connection so I'll take all of the blogs and upload them to local storage so here when we have internet connection I'm going to pass in local data source dot upload local blogs and then pass in the list of blogs which is like this and then we can return write blogs again and this makes sense right if internet connection is there get it from Super super based upload it to local storage and then return all the blogs that you fetched so hopefully this works now let's solve the error in in a dependency because we' have added a new Hive dependency and we've not passed that in so the blog repository requires blog L local data source and connection Checker so first let's go ahead and specify a new data source so it's going to be do do register Factory blog local data source implement ation here we need to pass in a box and to pass in a box I'll have to create a new box and we'll be creating a box right at the top so to initialize Hive we need to do two two things first we need to change the default directory of Hive so I'll specify hive. default directory like this and make sure to import Hive and what should our default directory be well to get that we'll have to use the path provider plug-in that we installed installed so we can do get application documents directory and we need to await this because this is a future and we can get the path of that place and that is going to be our default directory after that we need to create a new box and return that so here I'm going to have service locator. register lazy Singleton Hive dobox and then we'll pass in the Box name which is blogs we also need to pass in the name of Hive so we'll pass in like this and there we go so our Hive box is now registered I can go back to my blog local data source implementation and pass in service locator like this after that I can pass in service locator for the local data source and the service locator for connection Checker so our app is now up and running but you see we getting an error the error says that object of factory with type blog local data source is not registered inside get it and that is because we have specified blog local data source implementation over here but we forgot to mention the type the type over here is blog local data source so pass that in don't forget that and now if you restart the entire application the error should be gone and we get our blogs and hopefully the blog is now saved in our local storage now what I'm going to do is close the Wi-Fi then I'm going to restart my app and you see we have our blogs still displaying I'm still going to restart it and you see there was no loading indicator or anything the blocks show up quickly and they are coming from the local data source from the hi database if you want to confirm you can do it but I'm sure they're coming from The Hive database because this just show up so instantly and they're stored offline and we have done our caching process as well using the hive database and with that we should be done with our application let's see if we've missed anything by using a flowchart so we going to go over it from scratch we start the app we check if the user is authenticated if the user is we check if the internet connection is present if it is we fetch blocks from superbase if it's not then we display blocks from local data source and then all of that is done on the homepage if the user is not authenticated we display the login page and if the user already has has an account they can click on the login button go to the homepage so that's done and if the user does not have an account we go to the signup page so everything in our application is done our entire flowchart is completed I still want to do something and that is to refactor some code and I've made some bugs so I need to fix them so I'll close all the save files I'll quickly fix the bugs refactor some code and then we should be done with the entire Tut tutorial so let's start with the Box first so if you go to the signin page and there we need to pass in the email and password once you pass that and click on sign in and if it's a success we don't automatically go to the homepage we want to do so so to fix that we'll have to go to the login page and here listen for the OD success State as well so I'll add here else if state is au success in that case I want to do Navigator dot push and remove until because I want to remove this page and go to the next page so that I don't come back on the signin page and then I'll pass in the blog page. route after that's done we can save this file take this El if condition and put this in the signup page too because signup has the same problem also let's import the blog page and there we go after the application is started you can go to the sign up page and here pass in the name of the user so let's pass in tran email as dvan gmail.com and password as test1 1234 then we can click on sign up and we see we are taken back to the homepage that's good if I restart the application the state persistence should work and it does work so that's nice too so the login and sign up user navigation bug is completed the next bug I want to solve is that if there's any exception we get the exception along with the error message so if there was an exception Au exception that the password was too less of the user I don't want that o exception message to show up so for that I'll have to go to my Au data layer in the data source and here catch specific exceptions and then throw server exception based on them right now what I've done is in the O repository I've called those exceptions for example I've called the O exception here it doesn't have to be that way instead I can cut it from here and put it in the Au remote data source layer so here I can catch a particular Au exception because we're logging in the user and then we can remove SB Dot and then we need to throw a server exception not return left and instead of putting e do2 string here I can pass an e. message now I can copy this and paste this in the sign up with email password function to because Au exception can occur there as well so I can go back to Au repository implementation and here you see I've removed from the get user so it means I've removed it for the sign up with email password function too now I can remove the import of superbase flutter doing this helps us in two ways we won't get that Au exception message seen on the client side and the second is we don't have to import any super base related dependency in my o repository implementation so later on if I decide to change my database this dependency will change but nothing else in this entire class is going to change so that's good now I can do the same thing in the blog repository as well so I'll go to the blog data source and here I can catch specific exceptions so the exception I'll be catching in upload block function is the postgress exception so I'll pass in post grest catch e and then I can throw a server exception with e do message the postgress exception is going to occur whenever we use something like this when we make our calls to the superbase database because superbase database uses postgress behind the scenes and you can see this postgress exception comes from the package postgress so super base is just a layer around the postgress package then I can take this and put this in the get all blocks function as well because that's where we contacting the postgress database again so I'll do that in this upload blog image function we directly talking to the super based storage so over here we are going to catch another type of exception which is the storage exception so we'll catch e and then we'll throw a server exception again passing an e do message since there's no database call over here we're not putting postgress exception so I think we've done everything for remote data source I can go to the blog repository layer and see if I've put any other exception here and luckily we haven't done so so that's nice we are only catching server exception which we throwing from the remote data source so everything looks good so this bug is also solved again the only reason we do this is because we want to catch particular exceptions in the remote data source so that I get the message attribute and I can clearly display the error to the user not something like Au exception colon and then the error message we also do not want to display the status code to the user and that will be displayed if we just threw a server exception from here so keep that in mind so I think all the bugs are now fixed now I just want to refactor my code so I'll go to the lip folder in the inner dependencies do do file if you see there are like 22 lines of UT and as our application growth it's only going to get bigger and bigger so at one point there are going to be 100 lines of input and to get to the main part we'll have to scroll down a lot and that will waste much of our time so what I can do do is create two files one file is going to store all the inputs and another file is going to store the actual calls that are made the actual code we will write so in the lip folder I'm going to create a new file called in Itor dependencies do main do. file and in this file I'm going to transfer all my actual code so I'll copy all of this and paste it in Internet dependencies do Main dot this is my main code file and here I'm going to say that this file is a part of inore dependencies do file and in the inet dependencies do file I can say that it includes a part file that is in dependencies do main. do and this way whenever I import something like a new dependency or a new class all the import will automatically go in this file and this main do. file is going to have all the actual code so this looks much neater you might have seen this part file in the block as well so we had our Au block or our blog block and we had part as Au event and O State and whenever we wanted to import something in O event the import directly went in the Au blog. file so it's the same thing we did in in in dependencies do file another refactoring I want to do is if I go back to my add new Blog Page you'll see here I have my list written so whenever I have to update the list of topics that my app can allowed I I need to go to this page and update it that's quite a bad solution because later on if my app expands there's going to be a possibility that this list is used multiple times and I do not want that for example if you decide TR to add a new feature of sorting by topics or filtering by topics so you select one topic and all the blogs related to that topic pop up so you'll be using this list again so instead of copying this again and again why not have a centralized control over it so that whenever I need to update my list of topics I can do it from one place so I can cut this out go to the core folder create a new folder called constants and here create my constants do. file so I'm going to create a class constants which is going to have a static constant list of string which is going to be topics and that will be the list now I can go to add new block page and pass in constants do topics. map now whenever I want to update the topic I just need to go to this constants file and another constant we can have is no connection message so maybe you want to update your no connection message you'll have to do that in several repositories now instead of doing that you can create a constant over here saying static const no connection error message which is equal to let's say the error message is not connected to a network then I can take this no connection error message get out of this constants file go to the repository and here instead of saying no internet connection I'll say constants do no connection error message then I can copy this and go to the blog repository implementation and do the same thing so whenever we upload the blog we say constants do no connection error message and now whenever I have to update this I just have to update this string I have a cent centralized control now you might want to do this for everything for example the super based table there is a scope of having an error there so if you go to our data source like Au remote data source here you'll see we manually typing profiles instead of typing profiles I can store this in a superbase constants file a new class a new file which contains all the superbase related constants like profiles blogs and even the bucket name which I think was blog images and use all of that constants over here that would be a good thing too because there's a possibility that your table name changes or there's a possibility that you misspell this if you pass profile your entire logic changes and you'll get an error or maybe you're storing your data somewhere else we do not want that so keep that thing in mind now I know clean architecture might seem Overkill that's indeed true but only for simple apps like the one we built right now when you write bigger apps clean architecture will prove out to be a good solution I'm not saying clean architecture is the best architecture for your apps or programs the best architecture depends on your project this Reddit comment sums up everything pretty well about clean architecture so I would encourage you to pause the video and read this so that's all the refactoring I wanted to do and this marks the end of the tutorial as well I hope you understood clean architecture thoroughly I hope you'll be able to add new features to this app if you do let me in the comments so this is it for the tutorial thank you so much for watching and I'll see you in the next video
Info
Channel: Rivaan Ranawat
Views: 65,784
Rating: undefined out of 5
Keywords: flutter, flutter clean architecture, flutter clean architecture for beginners, clean architecture, flutter clean architecture tutorial, flutter clean architecture course, flutter clean architecture using bloc, flutter clean architecture full stack app, flutter course, flutter tutorial for beginners, flutter course for beginners, flutter clean code, flutter project, flutter blog app, flutter bloc, flutter get_it, flutter get it, flutter supabase tutorial, flutter bloc tutorial
Id: ELFORM9fmss
Channel Id: undefined
Length: 424min 58sec (25498 seconds)
Published: Fri Mar 08 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.