Flutter Course for Beginners – 37-hour Cross Platform App Development Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this massive flutter course will take you from being an absolute beginner to being able to release apps on the google play store and the app store bandit is a very experienced software developer and an excellent teacher hello everyone and welcome to this free flota course my name is vandal and i'm a google developer expert for flutter and dart and let's jump and jump right in who's this course for i designed this course mainly for absolute beginners so whoever hasn't even done a written a single line of code before i actually when designing this course i designed it for two specific personas one was a graphic designer who was working mainly with figma actually it doesn't really matter what graphical tool you're using photoshop or figma or whatever or sketch and the other persona was a project manager who's mainly working with jira so um i've made the assumption that you pretty much don't know anything about software development from before and even if you're a software developer you could perhaps jump over the things that you might know but if you haven't done a flutter development from before i strongly suggest that you actually follow the chapters chronologically which is the way i've designed this course basically so um as i mentioned i want when i design this course i want i wanted everybody to just follow the chapters one at a time and one after each other chronologically so um i highly recommend that you don't jump over chapters just because there's so much information provided in each chapter and i will be referring back to information that i provided in previous chapters in each chapter so i think it's very good if you can just follow the course the way i design it to be consumed which is chronologically and what you learn in this course is not only the basics but you'll also go from a complete beginner to being able to release your applications in apple's app store and google's play store and we're going to be using a blend of different tools and software we're going to be using visual studio code we're using firebase for the backend which i'll teach you all about we're using even figma as a graphic designer to create our icons and screenshots and even our loading screens so and there's lots to be learned and i'll take you through those steps and i don't make any assumptions about what you may know from before so i'll explain everything along the way so you'll go from absolute beginner to be able to be able to actually release your two applications which is the same code base in apple's app store and google's play store uh if you if you're attending this course please do follow me on social media and i'll really really appreciate it i'm evan.mp on twitter and also you can find me by my full name on linkedin that'd be much appreciated this course of course uh for free but for those who want to and are able to support me um then you can do that by buying me a cup of coffee on buy me a coffee.com van that so without further ado let's just jump right into it hello everyone and welcome to the first chapter of our flutter course um there are so many different topics that i could choose for the first chapter they're and they're all very important however after going through the material that i've been preparing for you for this course i realized that one of the absolute basic points that we have to go through is the developer accounts um for apple and google now if you're not familiar with the term of developer account there are basically what a developer account allows you to do is to release your applications on um apple's app store and google's play store as i mentioned in the introduction you may choose to follow along this course without actually releasing the application to the app store and the play store but even if you do decide to not release the applications on the aforementioned stores you will still for the optimal experience of development for ios and android you will most definitely need a developer account and the reason behind that is i mean it is quite deep to try to explain the actual reason behind it but from my perspective one of the most important reasons you may want to have a developer account is to create the so-called app ids so every application on ios and every application on android has an identifier which is usually something called a reverse domain identifier and it's kind of like um i still find it strange the way it is but some were somehow it was decided that every application needs to have an identifier and every identifier is kind of like associated with a domain name and a domain name is kind of like a website for instance if you have a yourname.com uh as your website then you would say that okay i'm gonna create an application for ios and android in flutter and i'm gonna call it fubar then it was somehow decided that your applications identifier would then in that case be if you reverse it then it would literally be your domain in reverse which would become dot your name dot your application's name i don't really know i mean if somebody's if somebody knows the reasoning behind it i would be glad to hear that and i'm sure that there's resources out there explaining why that is the case but it kind of feels like it's become the norm and we just have to roll with it so the reason i explained the app identifier is that when you set up your back end later when we set up the back end later together in that the client that we write in flutter is going to talk with our backend and store the notes retrieve the notes create a user uh sign in with a user etc etc that back-end setup also will require you to have your app identifier and even though you don't necessarily need to have a developer account to get an app identifier because an app identifier is just something that you decide okay here's my app identifier i think my website is called this blah blah and even though you don't actually need a website that's the thing but an app identifier is usually associated with a website so don't worry about it you don't have to have a website in order to follow along with these steps that i'm going to name here but it is still good practice to create your developer account in order to officially register your app identifiers and another reason that you will need a developer account for apple and google is that you will for apple um if you want to be able to deploy your application onto a telephone and not use a simulator then you will need to register a developer account and use some resources that apple provides you in forms of certificates and keys and profiles in order to deploy your application to a telephone or an ipad for instance and android the world is a little bit different in that you don't have to do the same process but in order to then submit your application to google for review later so that it can be available for everybody who has an android telephone or a tablet you will still need a developer account so it goes without saying that it is a very important step um that even if you decide not to deploy your application later to app store and play store it's still a very fundamental step so i suggest that you actually go through these steps that i'm gonna provide you in the first chapter and that's why i actually decided to have this as chapter one um sorry i have to just edit my notes a little bit if you haven't watched the introduction to this course and you're just jumping here i suggest that you go to the introduction and watch it i know it was about 34 minutes it was quite a long introduction but there are so many important points that i feel everybody needs to know before you get started with the course so please watch those if you see me moving my head around then you know the reason and i explain a lot of things that are like the fundamentals of this course and the reasoning all those decisions which i believe are so important that i still suggest everybody watched an introduction before they actually start with the course so so we've now talked about the basics um and if you go to why we need a developer account i believe i've already covered this in that a developer account is the utility is an account that you register for apple and google that gives you extra resources as a developer in order to be able to deploy your application and deploy your applications to the respective app stores now if we talk about developer accounts there are two main types of developer accounts one is an individual account and the other one is a company account um and for me the biggest difference between these two different accounts is the liability um and by liability i mean if you if you register an individual account then you as an individual are liable for that application and as users download your application and interact with it if they have any problems any for instance any there's any judiciary problems like if if someone for some reason believes that you're storing their data in the wrong way or that you're storing their personal information without exposing that and telling the users about that then they can personally hold you liable for for for instance breach of information or gdpr infringements or whatever it is so just know that you can register yourself as an individual for both app store apple's app store and google's play store but you need to also be aware that should you wish to do that then you're personally liable for any problems that will that may be [Music] occurring in the future so that's the personal account or an individual account and as a company account then uh you kind of like based on what type of company you've created um you may or may not be personally liable for um any damages that may be caused to your users and if they bring it up to you now i know this is all sounding a lot serious in reality what we are trying to do is not that big a deal but we are still trying to store i mean the goal of this course is to um at this course is to uh go through an application and create an application that can store users notes notes can be quiet personal and you're storing those notes then um on a backhand that you have full access to so you're kind of like storing user created data so it is very important that you actually treat that data correctly make sure that nobody except those who are authorized can access that data so um from a responsibility point of view it is actually a little bit different what kind of company account you want to create if that's what you want to create now because for instance in sweden where i live you can have a personal company account in that or sorry a personal company so you can register a personal company it means that you are personally liable for that company um and you can also create a company that uh it has like uh it's like an umbrella basically sits on top and then there are people who are directors of the company and blah blah so you're not personally liable uh and that is the same structure that you can find in many other countries i believe you asked germany sweden england and many other countries you can set up companies that are either a sole proprietorship or something called english is not my first language but it's something like that or you can create like a limited company that you have limited liability and you're not personally liable so these are the different types of developer accounts that you can set up so we can i mean that point i think we all understand now that you can create an individual or a company account now i think i mean i personally registered already an account as an ios developer and an android app developer so and since i registered a company account i can't go through setting up the exact same company again but at least i can show you some of the steps involved in creating those accounts so what we could do is to um now you can't see the screen right now but i will bring it up here so that you can also see now i'm gonna bring my studio here and i'm going to make this screen a little bit bigger so that you can see my screen better so let me also make this a little bit smaller on top so that you can see the content a little bit better so you can see here that there are two options available to you either you enroll as an individual or you enroll as an organization and it is strongly recommended actually um so you need to make sure that you have two-factor authentication turned on and so that's that's not a problem all this means basically as an individual it means that just you you will need an account you will need to set up an account however if you want to set up as an organization like if you have a limited company and you want to create an apple developer account that is linked to that organization is a little bit different because um you will need to set up something called addons or duns or i don't know how you want to pronounce the uns which is kind of like a it's a new thing for me at least but it is an identifier for your company that you either have been assigned to already um by i think there is a company called dmb um so if we go to let me see if i can bring the notes for that uh let's see learn more if you go to learn more here here dmb is called by done and bradstreet so there then we have uh the ability to register a duns number um for me i was one of the lucky people to have already been assigned a duns number for my company um by dmb because you either have um let's see if if they write it here you see it says dmv may have already assigned your organization a free uh duan's number before enrolling look up your organization to see if you have a duns number so you can just click on the link and we can go here and you can then select your region for me it would be sweden then i would write my company name some address information contact information etc etc and then you can check whether there is a duns number assigned to your company so i suggest that you actually do this by going to this website okay so that's for a duns number if you already have one but if you don't have one then you will have to create and request a duans number from dnb i would show you the website for dmb and the uns number right now but my browser is set up so that my locale is already provided to the browser which is swedish and then if i go to the dmv website you're gonna see everything in swedish and that doesn't make any sense just to read the information in swedish but i believe you can go to dmb's website um so if if i search for a dmb duns or dunes or here so this is a swedish localized website for dmb let's see if it can change the language um actually i can see here that they're very they're actually in sweden and i wonder if we can here change country let's just say international so if we go here let's see if he can um if there's any way to actually request a duns number like if he sir say b-u-n-s um and i can't see anything related to that to be honest with you so if you go back here i can see i can request the duns and here the locale is svse and here the locale was engb so what happens if we just go back to this url that we were on before and then i just change the locale does that work well unfortunately but i mean here the uns number um get a duns number okay that's good and then and you can hear say i'm an apple developer press continue oh it sends you back here um that was really bad so it says look up your organization in apple's website uh and when you when you try to get a uns number it tells you to go to apple's website um if we say that then okay legal business name etc etc okay so you will you will need to go through this process which doesn't seem to be completely easy to get a duns number you see requested the uns number so you probably just want to go to dmb.coms number.html and i i can't explain this complete process to be honest with you because first of all it will be a waste of time for both of us uh because these are so many moving parts and a third-party company that i have no control over so if i even try to explain their process it may change tomorrow so there's it's not a good investment of our time but everybody else has figured it out and i'm pretty sure that if you just go and say request the uns number you can just follow the process and then get your uns number but begin by going through look up your organization so you may already have been assigned a free duns number so do that first please but but if you have to request the uns number i believe there is a little bit of a cost to it and that is about 70 dollars if i'm 70 to 80 dollars at the time of recording this video so count with almost about a hundred dollars and hopefully not more uh hopefully actually a lot less about around um 70 dollars at least does that make sense i said so many numbers seventy dollars at least so um try to get your duns number at least that that's what apple says you will need now of course if you want to register as a company i can't stress this enough you will need a website i remember vividly when i registered a developer account at apple and they rejected my request saying that well your website doesn't have any content and they were right because i just created an empty website like a domain i regis i know i didn't actually create an empty website i registered a domain and there was no website so when you typed my website's name it was it would just not show you anything so um and they came back and said no your application is rejected because you don't have a website what kind of company are you so then i had to actually get like a hosting service and i have some content in there have like a support so if you are registering as a website sorry as a company as an organization you will need a hosting service you will need a domain provider uh you will need to ensure that you have a website because they're not the same thing if you have a host and you have a domain provider it still doesn't mean that you have content on your web page but what i realize is that if you register your domain and have hosting service make sure that you have a website just have some content in there say hello we are this business that business um we work with this and this if you have any questions contact this email and here's our phone number here's their address etc so you need to ensure that if you have an organization it is actually an organization it's not just like hi my name is fubar i'm sitting at home contact me if you have any questions not like that so and of course after you made your decision you start the enrollment process so now learn more continue enrollment on the web you can do and then you come here and you will basically need to provide your information and continue with the process now we're not going to go through this but the important thing i have to mention here is that as you go through the enrollment process as a an apple developer unfortunately there is a cost uh last time which is about a few months ago when i registered or i had to renew my registration you have to renew your registration for apple's developer account you have to renew it every year and as i've mentioned here the process is not free unfortunately it costs or last time i registered or renewed my registration it costs 99 and i believe it's been 99 for a very long time so if you're in sweden it costs about a thousand crowns if you're in england it probably costs about 80 pounds or something um and in the us it's about yeah just count with almost a hundred dollars so i used to be able to provide this like you have to have some sort of credit card or debit card to be able to pay for it so um after you've done that after you register your account as an organization you will have direct access then or an immediate access to your developer account and you can start developing applications etc etc etc so if you're following along with this um course and you want to deploy your application to the app store and play store please do this first get your developer account either as an organization or as a as an individual get that process out of the way because a developer account especially if you're an organization as i mentioned here is not a super fast process i mean when you get the account then it's simple it's fast and you're in there immediately but the process itself is a long process so um i remember for me it took about two weeks because i got one rejection took about one week for them to renew like to review the process the documents again so is not a fast process uh unfortunately it's like very it's yeah it's just long long boring process so get that out of the way if you can please um so that's for the long and not free part for ios and also one more thing that i need to mention is that if you're registering and you want to sell applications which is not the purpose of this course but if you want to sell applications then you will have to provide some banking and tax information so they need to ensure that the stuff that you're selling in different countries the money that is then being sent to your bank account will be accounted for when you're paying your taxes so and i believe that if you're trying to sell apps on the app store then you will have to fill in some forms with the u.s tax offices um i don't even remember irs i think internal revenue services or something like the irs i believe that you have to fill some forms like send the forms to them then they will come back with some sort of identifier to you and then you will need to use that identifier on apple's website in order to basically say that yeah yeah i know i'm selling stuff in the u.s i'm selling stuff in japan i'm selling stuff in sweden norway but i'm gonna pay taxes for them here in my country and that's what the form says here here is my name here's my company i'm an organization or i'm an individual so i have no company my personal identification number my country is this um is my address my phone number etc and then you send it to them to irs and then they come back and say okay now we know who you are and here is your um identifier number like a business identifier number bin or something they call it i think i don't remember exactly but i believe depending on whether you're a business or an individual then the number is a little bit different so if you're a business i think it's bin and if you're an individual is in i don't know so um i don't know what that dialogue was some bluetooth devices wants to connect to my computer i don't know what it is so that's that part it can be long and it's not free okay that was a lot of information um that's for ios now uh what we can do now is to talk a little bit about android as well and the good thing about the android process like setting up your account for as a google developer is that it's a lot more straightforward as you would expect from google and given that they're um even like sending updates to an android app to the google developer console is a lot more straightforward than it is for ios i don't want to scare you but it is a fact and you will know that later when we actually get to the end of this course where we release the apps for ios and android that it is a little bit more straightforward for google play store but you still need to sign up for a developer account so um i'm gonna take in my notes uh that i've talked about that so what we also need to know is that there is a url that we can go to i'm going to copy that and paste it over here so you see which one i'm talking about here then you can see that you can set up a developer account and once you've logged in so i'm assuming that you're logged in then you go to play.google.com slash console slash user or you zero sign up is where url it may change so let's just what you can do is just google google play console developer account or google developer account then you will end up in a url that looks kind of like this so so don't count with this url that i mentioned here because it may change that's what i'm saying and you can as it is for ios development you can either set it up personally as an individual or you can set up as an organization now i happen to have set it up for myself as an organization because i do have a company here in sweden so it is a lot easier for me to tie all my business relations with apple and google into one entity which is my developer account for sorry which is my company so it wouldn't make so much sense for me to explain this either to go through all the details but if you want to set it up for yourself as an individual just press on get started or if you want to set it as an organization just press get started there as you can see you can provide information about your organization and you can see here as well as soon as you say i'm an organization then they say okay what's the website so uh you can see if i don't have a website we recommend adding a website that represents your organization well kind of makes sense i mean if you're a company where's your website every company should have a website unless you're like a pizza restaurant or something even a pizza restaurant probably needs a website but we have a pizza restaurant here in our town that doesn't have website so they're on facebook um and you don't you probably don't want to say that your company's website is on facebook so um so yeah where are we here and if you say you're an individual then you come here and they ask for some other stuff but still interesting because it says enter the url of your website or social media profile uh so here you kind of have to need you kind of need to enter that as well so maybe you can get away with a facebook url i laughed about it but maybe you can get away with it i don't know but i don't recommend that to be honest with you because as you will see later in the course when we actually submit our apps to app store and play store there are a few key data points that you have to provide to both stores one is a privacy policy url and the other one is a support url um and there are also two other emails you have to provide so yeah four the emails the first one is the support email and the other one is a contact email and if you're if you're setting up a business account then i really suggest that you actually set up a website because if you set up a website and you have a domain you have an email provider then your email will kind of be like uh foobar at mybusiness.com it's a lot more professional to set up an email that is bound to that it's connected to your email to your domain than it is to say mr johnson gmail.com um i wouldn't trust a business that has a gmail.com account i kind of want to know that yeah here's a serious business that they have their own website and blah blah blah but on the contrary setting up a website setting up some emails doesn't necessarily mean you're serious either so but it makes it more dedicated if you know what i mean so um so yeah that's um the process for setting up an account also for as an android developer i think that's that's about it uh that's all i wanted to mention in this uh first chapter of our course uh i highly recommend that you get your developer accounts for apple and for google what you'll also need to know is that i mean i've talked a lot about now apple account and a google developer account but if you're if you're developing uh your application on a windows machine for instance if you're if you're trying to learn how to develop flutter applications and you don't care about releasing your application at all you don't have to do any of this just follow along with the course as usual no problem but if you're if you want to actually release your application for ios then you most definitely need to also have a mac because you can't build your application otherwise there are some tricks you can do you can like build your photo application then later on like a friend's macintosh if they have one or you can send to a service that's in the cloud and they build the app for you and then they will send it back to you and then you can submit it so or maybe they even have to submit it it's a bit hairy to be honest with you but um it's it's a complicated topic it is a little bit difficult to explain um for instance if you're on a windows machine you can't even have xcode xcode is the tool and the the entire like a chain of tool sets that gets installed on a macintosh in order to build an application for ios platform now why am i talking about this and the reasoning behind that is that if you're developing a flutter application then um flutter can be deployed on a windows machine um macintosh or collectively called as desktop web android ios five platforms at the moment and if you're trying to release your application and build it for ios for instance and test on an iphone or an ipad you can't do that on a windows machine unfortunately that's not there's nothing wrong with a windows machine it's just apple's fault for locking down their build systems and all their tools to macintosh so they haven't made the [Music] conscious decision or yeah they haven't made the decision to bring their tool system and tooling to windows unfortunately or linux swift which is the language to write native applications for ios can be run i believe on linux um on windows might be but its main platform is still mac i know that this is a lot of information also to learn but if there is anything i want to close this chapter the first chapter of this course with is you can learn flutter and follow along with the steps i'm going to provide in this course without having to register any accounts yet so that's point one point two is that you will need a macintosh if you want to release if you want to comfortably build and release your flutter app for ios if you want to release your application on google play store which is point three if you want to do that you will need to register a developer account on google play console as i've shown you here and i believe that's all that's all you need to know so some of you may already have all these accounts and don't have to worry about it but some may not know all this like if you're coming from a design and design background if you all you do is work with figma et cetera and this is somebody for important information that you'll need to know about because i don't want you to get like frustrated during the process so i just want you to have some information so that you can get started at least without without too much hassle all right that's it i think for this chapter i can take in my notes that i've explained everything i want to explain did take about 35 minutes uh it's not unexpected to be honest it's a lot of information and i kind of want to take my time with it it's important that you and for me as well to understand all this so great i think um that's it for this video so i'll see you in the next chapter hi everyone and welcome to the second chapter of our course now if you haven't watched the introduction to this course i really suggest that you do that before continuing with the course because there are so many points that i've explained in that introduction that i believe are so important to understand before continuing with the course so in this chapter what we're going to do is we're going to take care of some setup steps that are required for pretty much the rest of this course and all the other chapters that follow along after this one chapter 3 4 and etc so um we're going to talk about flutter dart dark pad and how to install flutter whether you're on windows mac or linux and we're also going to talk about xcode android studio and we're going to talk about a few very useful extensions to our code editor so if you're coming from a background where you haven't worked with any kind of programming language before um i'm going to take this chapter quite easy so if you're an advanced programmer already you may want to skip this and you already have like flutter install everything you can skip this chapter without a problem so let's start by talking about what flutter is well traditionally developers and programmers or software engineers however you want to call them they've been creating and writing code with their fingers in different languages and then they're targeting different platforms it's very important to understand what a language programming language is um versus a platform think of a platform as the the end station where a software ends up being run run on so let's say windows is a platform mac is a platform linux is a platform and ios that runs on all iphones is a platform android is a platform etc now you would have programming languages that you as a software developer would use in order to target those platforms to write software for those platforms so you use a programming language in order to write a piece of code and be able to run that code on that target platform okay so a programming language example is javascript python swift rust um what else is popular right now java kotlin all these these are programming languages so you as a software developer who's trying to learn flutter would use then dart as your program programming language as i will soon explain so that has been the tradition that a person sits in front of a computer and says okay i want to write a program for windows then they go and write some code maybe with csharp.net or maybe they will just use some other technology i don't know what's out there right now for windows maybe they would use vb.map and then they would be done and they will release the software for windows and be like okay i'm done now then someone comes in the project and says ah we need the same software for uh macintosh or we need the same software for some other uh for instance platform then you would have to go and write the same software uh exact same code pretty much for the other platform so this process would be very repetitive in that you would have to write the same software over and over again so things such as flutter came in in order to remedy that so saying that a software engineer sits at home or sits in the office works with a group of other people and a designer maybe or a few designers ux there is a product owner et cetera and then they would write the same code then which will then be run on different platforms so as a software developer you wouldn't have to maintain different uh very similar pieces of code that only can be run on one specific platform so flutter in its ground basically is a ui framework for running beautiful and writing beautiful applications that run on multiple platforms at the same time developed by google has been in production for a very long time it's uh tried and tested it's open source and if you don't if you don't come from like software engineering background open source basically means that the code that is written for flutter basically the code that makes up plotter is open to the public for uh finding bugs and also for contributing to it or maybe just learning from it so if you're for instance coming from a background of as a designer it's kind of like you have your figma file open to the entire world or your adobe xd source open to the entire world for for them to watch what you're doing as you're designing and also for them to be able to fix stuff in your design if they see it not working as it should so that's open source um so flutter is open source ui framework um developed by google what a framework means i mean if you're not coming from a software engineering background a framework is kind of like a set of tools uh provided to you as a software developer so you can use these tools take a bit of this one take a bit of that one in order to produce an output so flutter it in itself is a software but it's more precisely referred to as a as a framework because of it's a collection of tools so if you hear a framework just know oh there's a collection of things i can use to produce some output now that's what flutter is um but what powers flutter is a programming language language called dart and dart has been in the making for more than eight years is a language that at the moment being maintained by google and also is open source so anybody can contribute to it anybody can learn from it and and find exploits or maybe problems with it and it will get patched by the public or by google themselves so dart is the language the programming language that powers flutter you could say so now you know what flutter is and now you know what dart is and i think in the next step now what we can do is talk about a great piece of web software called dart pad now dark pad as i said is a web software or you could just call it a website that allows you to run or write your dart code maybe pure dart code or code for flutter and run it directly in your browser without you even having to install anything so just open your browser and as you will see soon we go to dark pad and you will see how it looks like so let me just show you a little demonstration here so here i have dart pad open and i can actually increase the size so you can see a little bit better i may have to rearrange some components here on the screen so you can see the screen better so i went to dartpad.dartlang.org and you can see here that there is a program written on the left hand side and i can actually yeah let this what is dark dark pad allows you blah blah text to be there so you can have context of what i'm talking about and you can see that the program is sitting there and you are allowed then to either change the program the way it is or click anywhere here to see documentation down here or press the run button so i'm just going to press the run button and you can see that the text hello got printed to the screen five times plus the number of times it was actually printed it's also printed on the screen so hello one two three four five so what you see on this side is the source code if you remember from open source so this is a source code written in the programming language called dart and this is the output of that program so dark pad allows you to write text here and just execute it and see the results immediately so that's what dart is i mean sorry dark pad is and we're going to talk about dart and dark pad more in the in the course but right now what we should do is to start by installing flutter because uh i mean you could say okay but flutter is just the uh ui framework how about dart well the way flutter is packaged by default is that it includes the dart programming language and its runtime so if the tools required to run any dart code it packages all of that in just one big chunk for you so you don't have to go and install different components like install dart separately in flutter so let's just then improvise and i'm going to say in here let's say install flutter okay then you go to this beautiful website called flutter.dev i'm going to increase the size here so you see so um we go there now and you will see this beautiful website here and what we're gonna do is just to press on get started and remember we press on get started but this website looks like this right now maybe in a few months or maybe in a few years it will change so you'll just have to find out a way to get to the installation part right now it's called get started and i can see it's located as docs.flower dev get started install then pick your platform here i'm on a macintosh but if you're on windows just click on windows and then you get instructions on how to install fodder and then or if you're on linux you can also do the same just get instructions for your platform now i'm going to mac and i'm going to click on mac and then i'm going to look at this information here i'm going to increase the size so it's a little bit easier to read and it says okay download the following installation bundle to get the latest stable release of the flutter sdk sdk means software development development kit i believe so it's just like series of tools for you to use it's just fancy words so then we're gonna do that let's just get flutter mac i'm gonna download it and it may take some time because it is actually quite a chunky uh bit of software as you can see it's almost 1.2 gigabytes so depending on your internet connection it could take yeah anything between a few seconds to a few minutes after you've done that then you will have to unzip that in some folder so what that kind of means is just i can see that my mac is already decompressing this zip file for me so i don't have to do that myself and it's already decompressed in this place so i'm just gonna click on it and i'm gonna show you its content so it kind of looks like this okay now that you have this what you need to do is to ensure that all these files are placed inside a location on your computer which is protected so that you don't accidentally delete it and it's also a good like um you know exactly where it is so by that i mean don't put it on a desk on your desktop and don't put it in like documents or anything it's not a document software what i like to do is usually to have a folder on a macintosh called dev so i will open terminal here as you can see terminal if you're not familiar with it is an application that you can control pretty much the entire system with it if you're on a mac or if you're on linux or any unix based system and if you're on windows you can also do a lot with your terminal so in windows that terminal is called cmd i believe as in command i believe on linux and mac it's called terminal i'm using a a terminal here called i term uh but if you're on vanilla mac os then you would go and open terminal like this which is just looking like that so i'm going to open i-term right now which is my terminal you can open the terminal that you're comfortable with i'm going to increase the size of this i like to place my installations for these pieces of software in my home directory which is denoted by this little funny character slash dev and if i look at the contents of this i can see i have a folder called tooling if i say tooling and look at the contents of it i can see flutter is right there so for me flutter installation you know this folder that got in that got downloaded for me in my downloads folder i would go and copy its contents contents and place it in this folder so if i say cdflutter and then you can see that i'm in my user dev folder tooling flutter so this is where i choose to put flutter now you can choose to put this downloaded folder anywhere else as the documentation tells you in the desired location for example so go ahead and do that pick a location and for me this location works for you it may be if you're on windows it would probably be like c backslash i don't know you could say dev backslash tooling backslash flutter this could be a good location for your tooling hot photo so i'm imagining now that you've done that you've gotten a folder and for me it's this one where you've extracted your flutter installation in now you can see that it says in this third step you will need to expose flutter's binary files to your system and what that basically means is that flutter as an sdk or a toolkit or a framework it has a lot of bits and pieces of software in it and some of these bits are more important in that sense that they're actually executable in that imagine that um on your computer whether in macintosh windows or linux you can have different documents some documents can be text sound documents can be images some documents can be i don't know what else they can be and or a word document for instance okay because i came up with another example or they could be programs a program is something that you can just double click on and a piece of software gets executed and then it will open for instance an example of the program is a microsoft word another example of program is a google chrome web browser another example of program is safari so these are programs and flutter comes also with its own built-in programs that do very specific and important things on your computer related to flutter of course um sorry i have to see my uh recording studio nothing you had to do uh it was just for me so these important programs that are inside the flutter installation which you just downloaded need to be exposed to your entire system so that you can work with flutter with with ease and that means if you're for instance from a design background it will allow you to anywhere in your terminal just write figma and figma app would open and that's the same thing with flutter in this folder you see we're in the flutter folder where you downloaded your installation and install it in this folder there's a folder called bin which means binary in here there are so many things that are important to the entire system to run you see flutter and dart these two i said so many but yeah there's pretty much two so these two binary uh executables need to be exposed to your system and the way to do that on a macintosh is to change your paths as is documented here so the way i like to do that is i go and change my so if i do a vim and look at my zsh rc i can see my paths and you can see it here so you see i've actually put that export command as it is stated here i put it here you see this may be a bit intimidating to be honest with you uh what all it's doing is that you see this file that i've placed here i don't know if i can actually zoom into it and if you can see i don't know how that looked in the actual recording but this is a sort of like a set of instructions to my terminal on this macintosh to tell it where different bits and pieces of binary executables are placed such as flutter dart python etc etc so when i install a piece of software uh in this way you see we just downloaded a package and just put it somewhere on our computer uh macintosh won't know about the stuff that's in it of course it won't so you have to tell it where those things are because otherwise if you don't do this step if you don't do the step three then every time you want to run flutter then you have to specify exactly where that flutter command is so for me it would be in my home folder dev tooling flutter being slash flutter but if you do this then you can anywhere in your terminal just write flutter and your macintosh or linux or windows computer will know where to find it so do that put put these instructions as specified here in your path and after doing that you may need to reload your path using a command on windows and linux called source and the shrc for me depending on which shell you have you may have to put that instruction in somewhere else on windows i believe you will have to modify your um environment variables i remember this from many many years ago let's see if you have to do that update your path you see if you wish to run flutter commands in regular windows console take these steps blah blah from the start search end and select edit environment variables for accounts so what you'll just have to do really is just to follow these steps i mean i'm going through basically giving you some of the basics of these instructions so you can get like a head start but these instructions can also change in the future so don't rely just on what i'm telling you please just go to the installation website here uh here as you see docs flutter dev get started install and try to follow along with the steps provided so after you've done all of this you should be able to be anywhere on your computer and just say flutter doctor now fluffer doctor is a very important command because it looks at your flutter installation and it kind of makes sure that it's in good health as denoted by the word doctor so because fluttering itself is a framework and it depends on many other bits and pieces which your computer may need to have in order for flutter to actually work optimally um flutter doctor will then go through a series of steps to ensure that first flutter is updated and that you for instance have android tool chain that you have xcode installed chrome blah blah so i mean this result at the moment looks quite fine on my computer but if you're running flutter doctor for the first time on your computer you may get a few problems uh some of the problems that you'll experience probably is going to say android sdk couldn't be found xcode couldn't be found because if you're running flutter on a windows machine or linux machine then you can't have xcode xcode is like the software provided by apple and only runs unfortunately on mac os and it's used for compiling or creating mac os ios and ipad os pieces of software so although you can run flutter on your linux and on your windows machine without a problem you won't be able to produce or test your flutter code running on an iphone unfortunately unless you have access to xcode and the easiest way to get access to that is of course to have a macintosh and that's unfortunately because unfortunate because yeah it's uh it's just not available for other platforms so you've run flutter doctor and it's it's basically gonna tell you that okay now i'm gonna assume that you're on a macintosh it's gonna tell you that okay uh xcode for instance uh you need to install xcode and the way to do that is you need to open app store on your computer and just type xcode here and go and install xcode on your computer um so depending on i don't know which version is the latest at the moment but if you're trying to develop flutter applications that and also make sure that they run on your ios phone or the ios simulator then you need to install xcode if you're on a mac sorry if you're on a linux computer or windows you don't have to do this step actually you can't do unfortunately this thing so once you've done that you also need to make sure that you've installed develop developer tools for xcode so let's see how we can do that developer tools xcode command line tools right let's see install from terminal there's a command that you can execute in order to do that and that command actually looks like this here i'll i will zoom into it so you can see better um it says sudo xcode select install so you need to issue that command in your terminal so if i do that and it says what's the password i'll enter my password and it says they're already installed so if you haven't done that please go ahead and execute this command in order to install command line tools for your xcode now the next piece after xcode that you will need is let's see if i can actually bring up so we've talked about flutter doctor that was flutter doctor and we also talked about installing xcode so i'm now bringing that up a little bit late and but now the next step is to install android studio so what android studio is is like the equivalent of xcode but for writing android specific applications now for in order to write flutter applications you don't need android studio per se but you kind of need the sdk manager now both ios and android um for programmers they provide you with something called an sdk just like flutter is an sdk or tool kit ios and android also provide you with sdk in order to write native applications and since flutter utilizes these native capabilities of each platform in order to for instance create an application that's compatible with ios or android it will utilize the native uh components or sorry or the native pieces of software namely called xcode sorry mainly called ios sdk and android sdk so you need to download android studio so you get access to the sdk manager so you can install an android sdk now xcode in itself when you download the latest version of xcode it comes with the latest version of the ios sdk but android studio doesn't do that wait a minute yeah it probably does in the latest versions but we can check that out so if you go to your browser and just say android studio and then you open up developerandroid.com let's just go there and then you can just click on download android studio and then there are download options and you can see there's available for windows mac and linux so then please go ahead and download uh your android studio and i can see the for macintosh is a package so you can install it easily you don't have to unzip anything and for windows is also like an executable so tar gz as well for linux so now let's say that you've done that and now after doing that then you should be able to bring up android studio let's see i'll bring it up here now when you bring up your android studio it will just pretty much be empty here on the screen and you'll get some tips and tricks how to use android studio but the important thing for you here is to be able to install uh the android sdk so if you go then to tools i believe there is an sdk manager right here so just ensure that you have an sdk installed for me i have android 12 installed here so ensure that you have one of these sdks ready for you to use by flutter and as soon as you've done that then when you run then your um clutter doctor command and the part about android sdk is going to be ticked here uh sorry the android studio so that's that so we've talked about android tool chain which is the android sdk you can see we've talked about xcode chrome is just a web browser if you want you can have that if you're developing app flutter applications for the web it kind of is necessary um and then this you're probably if you're just getting started with flutter you're not going to have this vs code part ticked because vs code is a a code editor an open source code editor provided by microsoft and it is the code editor that i'm going to use for the entire course for this entire course as we go on and to be honest with you i've tried android studio and i've tried vs code for flutter development and i can highly recommend that you use vs code just for its sheer performance it's for its simplicity extensions and its ability just to really focus on a simple editor without bothering you with lots of bells and whistles so it's a preference though some people use android studio for flutter development and some people use vs code so i don't think one is better than the other it's completely a preference so so that's for android studio and the android sdk so now let's go ahead and install visual studio code which is the tool that i'm going to use for this course so let's bring up a new window and i'm going to say install visual studio code and i'm going to bring the window up here so you see let's go here and and you can download the one that you prefer for your computer i've chosen mac and for me specifically i have a macintosh with an apple silicon so i then choose this one mac with an apple silicon and then it's gonna download that for you automatically so it's just about 200 megabytes i think or actually 100 megabyte only after you've done that just on a macintosh you would go and put that on uh in your applications folder so i'm actually gonna delete that which i downloaded just now because i already have vs code on my system so that's for visual studio code um so let's go ahead now and now that we've done that i'm gonna talk a little about talk a little bit about um some extensions that we're gonna use in visual studio code so let me bring up my terminal and um you know we don't need that let's go and bring up visual studio code um and then i already actually have so many visual studio code windows open uh but i can just say new window so you see how visual studio code looks like and then let's see don't show again okay so this is pretty much how visual studio code looks like so it's a very simple application to begin with um now what we need to do for this example is to enable a few extensions now the first section extension that we're going to enable is called arrow lens and you need to go here on the left hand side find extensions and just type error um if i can type air and just say airlance just like that click on airlands and just press enable or install i believe it's called so error lens allows you to see errors in line without you having to click on a specific line of error basically so it expands the entire error as you're coding you will probably have some errors in your code that error will be then displayed right there in front of your face in its entirety so you don't have to press a little small button to be able to see the complete air so it's a fantastic extension to be honest with you now the other thing that you'll need is something called a bracket pair colorizer and that bracket pair colorizer is something that is already installed in visual studio code it used to be a an extension that you could download but it was so popular that microsoft has added that internally to visual studio code so you don't have to do that manually sorry by installing an extension so now that we've talked about that the next step is to actually install flutter and dart extensions so here just type flutter do that and then just click on the install button i've already installed that so there's a disable button for me here the flutter extension and then you'll also need the dart extension so just type dart and then install that as well so after these two installations we also need to install another great extension called block bloc i'm not going to go into the details of what block is because we will learn about block a lot later in the course but it is just a great extension to have as we go on you're going to learn about it so i can't really explain exactly what it is right now but just install it and i will tell you more about block later in the course i promise so that was basically installing a block now when you start up your visual studio code it probably doesn't look like the way it does for me and that is because i have a custom theme installed on my visual studio code called tokyo night it is a very very mellow dark theme as it's called and scenes in visual studio code can be installed just like you install an extension so if you like my theme you're more than welcome to go in into extensions and then search for tokyo night and just install it so that's it has different theme colors as well this is the one i use tokyo knight actually i use this one tokyo night so if you want that theme please go ahead and install it and now that we've talked about that we come to the last point that i wanted to discuss basically in uh before we wrap up this chapter which is our chapter two so now that we talked about a little bit of setup for setting up your flutter installation and setting up your text editor which in this case is visual studio code in the next chapter which is chapter 3 we're going to talk about dart programming so before we actually jump into writing flutter applications we're going to talk about how to write code in uh dart or at least understand like the basics of dart so without further ado let's close up this chapter and i'll see you in the next one hello everyone and welcome to the third chapter of our flutter course in this chapter i thought maybe we could focus a little bit on um actually not a little bit but quite a lot on dart as you know from the previous chapter we know now that dart is the programming language that powers uh flutter so it would be a good idea for us at least to get a little bit of introduction to dart how it works a little bit of its internals different data types functions methods classes and this chapter as well um just like the entire course i'm kind of assuming that you haven't done any programming at all before so i'm going to take things very slowly uh take the concepts one at a time introduce them to you so and i will give you some references to read more about the topics as we won't have really that much of a time in this course to go into detail about everything so um the goal of this chapter is to basically get you started with programming uh dart uh and writing your apps then later for flutter in order to do that we need to have a project set up and by project i mean you need to have some kind of a playground set up so that you can start writing dart code and then you can try it on for instance a telephone or a simulator or what have you now um a lot of people would rather go to dark pad as we saw in the previous chapter and start writing their code in dart pad that's one way of doing it but since in this chap in this pro in this course we're gonna write an application release it for ios on android um it is safe to say that that we can literally start actually creating our real project here and now so that we can then later build upon it rather than writing all our code in dart pad because you can then by doing by writing your code in an actual flutter project you can get used to how we work with flutter as a whole so i think this is a little bit of a time invested into later chapters as well where we're gonna work and continue working on the same project so we have to just set it up once but at the same time there is a little bit of a value in not blending in too much of our test code like what we're doing in this chapter with what we're going to do later in the actual application if you know what i mean so so i think it would be better now for us to set up just a test application and then keep working on it and then later on when we start doing the actual application then we create a separate project for that so now let's then do that together so i'm gonna bring my face down here so you see the entire entire screen i'm then going to create a new terminal window and bring it up here on the screen so you can see it and i'm going to increase the font so it's a little bit easier to spot what i'm typing so let's go to a folder where you try to or where you keep your uh projects for me i go to dev projects and i have a folder there called flutter so i try to put all my flutter projects in here then in order to create a new flutter project what you have to do is to issue the flutter create command and this create command is already shipped inside flutter so if you say which flutter this is going to go and find the actual flatter binary if you remember from the previous chapters where we installed flutter it's going to find the flutter binary and then call the create command on it so if you say flocker create it expects you to kind of like provide it with some sort of a name of a project so let's just say learning guard learning er mean dart so that's the binary that's the command and that is the name of the project okay so uh this is the easiest way to create a new floater flutter project in my opinion at least so let's execute that command it's gonna do its thing and what i'm gonna do then is to as you can see it's created a new folder called learning dart so let's go and i'm going to say cd learning dart and then i'm going to issue a command called code dot and i can actually bring this a little bit to the right so you can and also do like this so you can see what i'm typing as you can see i've written code dot and what code does is that it brings up visual studio code so it's just like a command that you can issue in order to bring a visual studio code and um if if i just bring up visual studio code the way it is right now and for instance you can see it you can't see it right now but it's because i have a separate uh screen here i'll bring up visual studio code as you can see here by hand there is a good extension where there is an ability for visual studio code to install this code shortcut for you in terminal in your path so if you say which code it just says user local bin code so it's just an executable that allows you then to open up visual studio code with a path like so you can say open a visual studio code in this folder so you can just say code dot so and you can do that in visual studio code you can allow that to be installed by doing um command shift p on macintosh or control shift p i i believe in windows and linux and there is this little command here that says shell command install code command in path so if you execute that once then it's already set up for you you don't have to do that anymore so if you'd like to be able to say code dot in terminal and open the current folder within visual studio code without you having to open visual studio code manually and then doing file open then i suggest that you do command shift p or control shift p in visual studio code depending on which operating system you're using and then choosing shell command install code command in path so i've already done that so i can just say code dot and i'll bring this up here so as you can see this is the basics of a simple um flutter project that you create with flutter create now visual studio code has a built-in terminal so i don't have to have this terminal window open anymore so i'm just gonna close it okay and i'm gonna make this full screen increase the size a little bit so you can see better and perhaps i could even remove this flutter logo on top right so you can see the content a little bit better as well so that's the creation of our simple flutter project now in order for this flutter project to run and you be able to run this application and like keep testing your project you would have to select a target and you do that with command shift p and then choosing flutter select device so you can just say flutter select device enter command shift p is on macintosh and ctrl shift p i believe is in linux and windows so do that command shift b is a very important command you're going to use it quite a lot in this course so just learn that please um then i'm going to say select device and i'm going to choose since i'm on a macintosh and as you saw earlier we have xcode already installed xcode comes also with the entire ios sdk and also with the simulator i can choose to run our application on ios simulator or i can choose to run it on an actual phone now for this um i believe i don't know if you've talked already about scrcpy to be honest with you i'm just gonna search in my notes um to see if you've talked about that and if you just give me one second i'll just check here i believe we're we're gonna set it up in chapter six so we haven't set up scrcp cpy yet so for that purpose i'm just going to say select device and i'm just going to say start ios simulator so that is going to as you can see start up by your simulator and that for now is like the best way for us to test our application so while this is connecting um i can show you a little bit around as well we have as you can see lots of files here already created for us we're going to go through some of these um but one of the most important files that you're going to need to get used to used to is this lib slash main.dart and this is where like the majority of the code is written so uh this is his contents at the moment um let's see what it's doing with the simulator i'm just gonna have a look here um it's taking a little bit longer than expected so what i'm gonna do is i'm just gonna kill the io simulator manually this shouldn't this usually doesn't happen but that's okay if it does happen then you know how to deal with it just close the simulator um and then i'm just gonna go to command shift p select device and then start ios simulator fresh so it's starting right now okay so that's our simulator and i'm actually going to decrease the size of this a little bit since i realize that it is a very large font so this is our main dart file this is like where the flutter command line um command has created it is the file that has been created for us so we don't have to play around with it too much to be honest with you at the moment um for the purpose of this chapter we're just gonna have a look at um basically kind of like exploiting this uh code so that we can inject our code into it so we can learn dart a little bit so you don't have to understand all of this code the way it is right now there's lots of comments and etc so so that's that part so now that we're here and then you can see we have a little simulator here and in order to run this application on this simulator since you've already done the flutter select command you just go to run and you say run without debugging for now so since the simulator is already selected then it understands that it needs to compile this project for my simulator so um and we're just going to give it some time depending on your machine and like what you have for specifications on your machine this this command could take anywhere between a couple seconds to maybe 30 seconds or even more and i'm not sure how long it's going to take for a fresh flutter project to be honest with you to start running on the simulator but it took about 21 seconds so or 22 seconds so um i will bring up the project now and this is like the basic flutter project i'm not going to go into details about how it works but you can press the plus button if you want to so but what i'm going to do i'm just going to close this widget inspector that was opened automatically and i'm just going to bring this a little bit down so that we can see the debug console okay so that's for setting up our project so that part is done now the first thing that we need to talk about when we start talking about dart is the concept of keywords now since i'm assuming that you haven't done any programming language in any other place before um you need to understand what keywords are they're very important in understanding any programming language basically and keywords are um [Music] concisely explained there are words that are reserved for the programming language that you cannot use for anything else than what the programming language intends those words to be used as i know that sounds a little bit difficult but i mean there's no real good analogy in like if you're coming from figma if you're coming from a design world what a key word could be because in a design world you're not really talking in terms of code with your product or with your software where you're designing your stuff but when you come to programming language as you know it's a language so words mean stuff in in a programming language so a keyword is as its name indicates is a word that has a special meaning in that particular particular language and i provide a link here for you that you can check out but i'm going to open it up and bring it to the screen here increase the size a little bit so we can see better uh have a look at my screen here yeah and you can see this is a part of the documentation for dark programming language that explains what keywords are in dart and you can see there are some words that have special meaning like show import extends async await break so you can say that the language the dark language is made out of these keywords that is pretty much it it's just like series of keywords like the things that you tell the language that hey i want to do something and then it says okay what do you want to do then you say okay i want to do this or this or this so special words for the programming language so that it understands what you mean basically so that's for keywords um for now we don't have to really go into so much more details about what a keyword is but for now just understand that a keyword is a special word in the programming language language's brain kind of so that you can talk to it it's your interface with the programming language to make it understand what you want to do okay and please check out the link that i provided here to understand more about keywords okay so we've talked about keywords i'm just gonna check it in my notes so that we know we've talked about it now the next concept that we need to talk about are data types um if you for instance come from a design background then you have different tools to work with for instance you may have in your design system whatever you're using if you're using product from adobe or if you're using for instance figma or whatever visio or whatever tool you're using then there's like a set of components that you can work with for instance you can drag in a text field or you can drag in an image field or sorry an image or you can for instance assign assign a color to a text so these are all like things that you can do with that software now a data type in in a programming language like dart is that type of a thing for instance you would say i have some data in my mind okay what is it it's the first name of a of my friend okay his name is uh jack or whatever um and then you would say okay what type is jack is it a number no is it like um is it a list of things well yeah it's a list of uh characters yeah uh okay then it's that is this data type or you could say i'm thinking about my age my age is let's say i'm 37. okay what is 37 is it a list of things well yeah it kind of is a list of numbers list of digits but it's also in itself a number so then there has been this convention like convention in different programming languages and every program language language pretty much that you can use these days has this concept of data types data type is as its name indicates a a specific specific name assigned to to a series a specific name assigned to a data that is bound to be of a specific type as well so for instance in dart you have data types called integers or you have strings or you have arrays and sets which we'll talk about soon but a data type just for now though it's just a stamp on a piece of data to say that you're of this specific type so you could think of a data data type as a nationality you could say like every person coming from sweden is swedish boom that's his data type so it's just a categorization of data based on their appearance or based on what they actually hold so for instance you can say here's a university full of engineers and these are software engineers these are mechanical engineers so the software engineer is a data type it or is a person type a category type so putting stamps on things based on the categorization is kind of what data type does and in short i mean you just have to know that it's just a categorization of things based on what they hold so and there's and there's a website that you can read about uh dart data types and it's right here i don't know if you've i've if i've provided it here on the link below as you can see dart core library html so um and here you can read more about dart data types but we're not going to go into so much detail about all these right now just know that data type in dart is or any programming language basically that has data types is a categorization of data based on their appearance or contents now let's talk a little about something called constants in dart a constant usually in programming language languages are values whose value cannot be changed that's a little bit meta but uh let's say for instance the value of um a value of 10 it's a number it cannot be changed 10 is 10 and it will always be 10. um or your name that is a constant although you can go and change it but as long as that is your name it is a constant so um another example of a i mean there are so many values that can be constants which will actually be quite abstract for me to be able to explain right now but just know that a constant is a value whose internal data cannot change during the during where you're writing your program and also during when you're running your program so um that is kind of what a constant is uh but there is also this uh notion of a compile time constant and a runtime constant and i i mean you don't have to know about uh like those different types of constants right now just because like in dart a constant is a constant whether it's runtime or compile time is constant it's just just a constant as you'll see soon but i still believe that it's important to understand the difference between compile time and runtime when you're talking about programming and when you're becoming software developer and i hope by the end of this course you'll actually become a software developer if you're not already um that would be really amazing uh but the notion of a compile time and a and runtime is very important to understand and developers like to um make a distinction between whether something has happened during compile time or something has happened during runtime and compile time is or before i explain compile time maybe i should explain compile compile is where you take the program that you're writing here and you tell the computer that i want you to package this up so that i can run it later on x and y machine so that process of packaging things up simply said is in very simple terms it's called compiling or a compilation okay so um from where you start writing your program with the hand with your fingers until where you package it you're pretty much just compiling it okay but when you run it like we're running it at the moment on ios simulator that session from where you start outputting your program into this device and for it to run your program from that moment on then the distinction separates into runtime so you haven't compiled time and runtime and a constant is a value that is the same during compile time and runtime so its value doesn't change so the value of 10 is 10 while you're writing your program and also stays the value of 10 while the program is running so that is a very simple explanation of a constant so now let's put constants and data types uh in practice now in this project that was created for you by flutter create in this in this line of code as you can see it says void main we're not going to talk about exactly what that is but just press enter at the end of it and just write final and i'm going to tell you what final is soon and just saying name is equal to foo okay this is there's lots going on in here and i'm gonna tell you um what is actually happening here um but i before before we actually go through all these details let's let's add something here called a constant so i'm just kind of saying const age is 27 or yeah 27. as you can see this is how you write code in dart you start by a keyword usually or a variable name or something as we're going to talk about it but const is a keyword okay and it tells dart that what is following here is a name right after cons i'm going to write some name and in that name then i'm going to basically say okay i'm adding the value of 27 to this h i'm sorry about this my dog also barking a little bit so what is happening here is that you're telling dart that i'm putting the value of 27 into a constant call h and you can refer to this age later for instance you can say then const age twice the age you can say is equal to age multiplied by two and this is also constant because at compile time word dart is basically trying to understand what you've written it says okay you said 27 and then you're saying 27 is a constant so its value is never going to change and if you tell me 27 multiplied by 2 that also is a constant because both this side and this side are compile time constants so that's that's what we mean by a constant it's a value that is specified during compile time and it and it cannot change so also it's important to know that notice that your learning guard and here is sorry i have to just take some items in my notes to make sure that i've explained all of those to you um you can see here that every line of code in dart needs to end with a semicolon and that tells dart that yeah you're starting a new line of code of course you can put two lines of code like this but if you just press save there is a program automatically running in the background which is called dart fmt which is the dart formatter which is going to format your code and prefix it so if i like put a lot of spaces in here and just press save you can see upon doing command s on mac or control s on linux and windows upon saving dart formatter is gonna kick in and format the code for you so just a little hint um okay those are constants so we've talked about that now let's talk about variables a little bit a variable is usually anything that contains a value that is not a constant i mean i think that's like the simplest way of explaining what a variable is um a variable as a name indicates it can vary and that means that the data that it holds it doesn't need to be constantly the same it means that from where you start the program you may actually assign a value to this variable and you may also change that variable depending on what type of variable it is um so there's also this notion of a final variable in dart which we'll talk about soon so before we do that let's go to this main function here and you could just say um var name is fu and here what i've done is that i've created a variable indicated by the var keyword whose value is foo or let's just say alex and semicolon to end the line now if i want to change this value all i could say here is to say name is equal to anthony or whatever now this is basically us assigning a new value to this variable saying anthony um as i said there is also a no the notion in dart for a keyword called final so you could just say final name equal to alex and it's it's a little bit strange because final is also a variable whose value cannot be changed so you may be like okay what like what kind of a variable is that like how is that not a constant now there's a little limitation because you you may try to like say const aim alex but this as you will see later in in the in the course final gives you the flexibility to assign a value to your variable a little bit later maybe in the process of creating it but it still indicates to dart that the value of this variable is not gonna change after it has been assigned to it's a little bit yeah it's it's it's just a little bit confusing maybe at the moment so let's just say a variable is like a constant but its value can be changed let's just leave it at that okay so uh that's it okay now that we talked a little bit about a little bit about uh variables let's talk about functions so um i didn't specify exactly what this is just because we hadn't really come to functions but a function is a body of code is a grouping of series of lines of code one to n number of n lines of codes that is logically uh grouped and it can it has a few properties uh one is its return value here indicated by void the other part of its information is its name followed by a pair of parentheses an open parenthesis and a closed parenthesis in which you will write something called the function arguments or parameters um it's pretty much just like uh imagine like a box where you input things in it it does some processing and then it outputs that stuff whatever it wants to output so what we could do here is to create a very simple function for for ourselves by as you see as you saw before or as i mentioned before what you write for a function in the beginning is this data type i mean what data comes out of this function and um and here let's say we want to add someone's first name and their last name with a space between it so if i say foo as the first name and bar as the last name then the full name should be fu bar and with the space in between so as i said then you need to specify the data type first what you're gonna return and if you looked at the documentation that i provided earlier there's a data type called string which is a series of characters basically it could be a name a family name address of your house or whatever and that's a data type is string okay so we say we're outputting string and then you say okay what should this function be called um there's a convention in dart that your functions should follow a camel case naming convention basically in camel cases if you for instance say in english my function should be called get full name that's my function name but you cannot have spaces in your function function names in dart or pretty much every programming language that i know about then remove all the spaces and then except for the first word change all because uh cons all the other words uh first letter to uh to uppercase so it was like this before you could actually change them to uppercase first and then remove the spacing so this is this is how you should write your function names this is called camel case full name okay we said that we also have to open parenthesis now let's just say then we need to uh specify somehow that we're going to accept a first name and a last name well what kind of a data type does a first name have well it's kind of like a string it's a name it's a series of characters so let's just type string here and then we want to take a first name and we know about camel case now so let's just say first name is uppercase and remove the spacing so first name hey that's the parameter and then you want to go to the next parameter so just say comma and then you want to say string last name you take the first name and the last name now we also said that after the parenthesis after you have accepted your parameters you want to go and create like your curly brackets here i don't know actually if i mentioned that before but every function is either its body or its logic it's either followed by equal greater than sign which we're going to talk about later or sco uh is by curly bracket so we're just going to use curly brackets now there what you want to do here you want to take the first name and add a space to the first name and then follow that by the last name so you need to you you need to tell dart that that is the data you want to return and thankfully there is a um there's a keyword called return that tells dart that you want to return some value from a function so then what you're going to do you're going to say i want to return what the first name and i want to add a space single quotes space us last name right so i mean this is a very simple implementation of get full name so um however there's there's actually a better way of doing this in dart and i'll explain it to you right now and that is by formatting your strings so let's say that you want to basically tell dart kind of like how your result looks like and you want to ask dart to insert the first name and last name into that result for you and that's how you'll do it like this you say okay i want to return a string denoted by the single quotation marks here and you can also do a string in dart with double quotation marks but i'm going to explain that a little bit later so let's say that you want to return the first name in here but if you say first name what's going to happen here is that it's actually going to take this first name as has you written in the string so when you get this return value it's actually going to say first name not the value that you pass to this i know it may be a little bit difficult to understand when i say the value that you pass to this what does it even mean uh so let's put this actually to test first okay go now into this build function as you can see here on line 16. now it may not be on line 16 for you but for me is at the moment on line 16. just find this class my app stateful stateless widget and find this widget build stuff that's written there create a new line here okay and just say full name or sorry say print as i'm writing it here print and then just say what do we call our function get full name see here and it says okay what's the first name i'll say quotation marks who and the last name is bar and ended with a semicolon so and ignore this call for now sorry this uh warning avoid print calls and production codes so okay so now we're calling that function this is the it's i mean it's called calling it's called invoking it may have other names but usually programmers call this calling call the function and these are the parameters that you're passing to this function okay so uh the i mean there are two words used for in in the programming world to explain these parameters like with with name and that is called a parameter or an argument i mean they're used interchangeably the meaning of them is kind of like getting uh convoluted in to the point that no one knows which one is which but you could just use parameter or argument and everybody would understand what you're saying so but there's a little bit of the difference which i'm not going to go into the detail of but if someone just says call this function with parameters or arguments you know at least what you're doing okay foo bar now we're printing its value all you have to do in order to execute this code is press command s and you will see the result outputted here now what we did here um what we did here was very very key feature in flutter called hot reload as you saw i didn't execute my code again i didn't press like the run button again i just said save now saving in flutter triggers an action called hot reload hot reload in flutter is it's a whole topic of its own which i'm not gonna go so much into detail of but what hot reload does really is it looks for changes in in your code hierarchy without complicating it too much i'm just trying to phrase my sentence right so that it's um not too complicated for this chapter it looks for changes that you made to the code and executes only those changes okay and in the process of executing those changes it might execute everything else that is in its uh in its path and by doing a save this function gets called somehow magically which i'm not going to go into right now which in turn then calls or invokes our function called getfullname and its value will then be passed into another function called print okay i hope that that made sense uh and as you can see the result isn't really what we expected it just says first name and that is because here we said return first name and as you can see if you put first name like this inside your string it becomes its own string it has nothing to do with this anymore if you remove these quotation marks however then it says oh first name is this parameter you see it actually highlights it so then if i press command s on mac or control s on linux and windows you will see foo being printed to the screen okay you can also say last name here and it will say bar right and know that no also notice that when i'm changing these things it's not executing immediately automatically i'm pressing command s so just keep that in mind please so so that's for a function and but before we move on explaining the basics of a function i want to also explain a little bit about string formatting and that is we said that we're going to put first name and last name because this is what we did in the beginning first name plus space plus last name and this wasn't so pretty because it's like doing string concatenation in a very old-fashioned matter in a very old-fashioned manner yeah i think i said it right the first time but what you want to do here is to uh use uh garth's built-in formatting capabilities and you do that by first saying that okay i want to return some sort of a string and i want to have first name space last name but as you saw this earlier if i command s or control s it just returns those strings exactly as i've written them not the parameters what you can do is just to put a dollar before them and you can see their coloring now changes depending on the theme that you're using or depending on the text editor that you're using if you're using android studio it may not color it the same way or if you're using visual studio with a different theme on a different maybe platform you may not even change the color but for me at least you can see that the change the colors change so as to indicate that now i'm not actually returning the string exactly as you wrote except on returning the parameters that are here so command this and now you can see that the result is full bar okay so that is the basics of functions in in dart before we move on from functions i also want to explain quickly that um a function doesn't necessarily have to return anything and that means that you may have a function here that wants to just print some data to uh the screen or to here to the debug console and you can just call it print my name and parenthesis and curly brackets and as you can see here i can just write the name of the function without any data type to be returned but it's a little bit of a convention that you actually tell dark that this is a void function meaning void is a key word as we talked about it earlier in the beginning of this chapter void is a key word telling dark that this is a function that doesn't return anything and as you can see dart is completely fine with this function being completely empty meaning that well yeah you said you're not returning anything you're probably just gonna do some stuff in here so i'm not gonna bother you with some errors saying oh you forgot to do something but as soon as you change the return value or the return data type of your function to for instance string then you'll get an error saying that oh yeah the body might complete normally causing null to be returned blah blah you don't have to know exactly what that means but essentially what that means is you're telling dart that you're returning a string but you're not returning anything it's literally looking for the return keyword saying that oh you missed it so you could silence that uh error by saying return an empty string semicolon so i think this pretty much explains the basics of um functions to be honest with you there's lots more to learn about functions and as i said functions can also be like written using this syntax and this syntax is used when your function is very simple or in that it doesn't need to break into different lines of code by a semi-colon so a function who has a very simple logic you can just skip writing these square brackets no curly brackets sorry and you can just say you see i will remove this put equal sign greater than sign remove the closing curly bracket and then you can remove the return statement and that's it that is a shorthand it's a function shorthand in dart and you could use it simply to simplify kind of your code some people may like it some people kind of may be against it just because it's um it kind of splits your code into two different styles some functions are with uh curly brackets some functions are with this pointer thingy and uh kind of depends on your and you on you and your team to be honest um i know usually from my um from my experience usually we software developers like to follow conventions so in one in one project the developers may decide okay we're just going to go with this convention and since using curly brackets involves the ability to have both complicated and simple return statements in a function it's actually preferred as a convention than using this syntax simply because this syntax doesn't allow you to split your code into separate lines of code it has to all be in one statement so if that makes any sense so i think i think that's it for functions and now we've talked about functions arguments return values we talked about variables constants data types and keywords in dart and these are such important parts of learning how to program with dark and flutter that i think you need to spend some time and experiment with them so do some experimentations on your own for instance take not don't take just the first name and last name just take for instance someone's address someone's age different play around a little bit with different data types like integers different numbers have a look at the link that i provided earlier which was here i'll bring it up again so you can see that have a look at this link and have a look at the different examples of different data types because in this in in the upcoming chapters and in the uh rest of this course we're going to play around with a lot of different types of data types so i think it's important that you have a look a little bit at the documentation as well so let's leave this chapter at this point and then in the next chapter we're going to talk a lot more about more advanced dart programming language features so thank you for joining me for this chapter and see you in the next one hello everyone and welcome to chapter 4 of this flutter course in the previous chapter chapter 3 we talked about keywords data types constants variables and some basics of functions and in this chapter we are going to as you can see on the captions here we're going to focus on control statements and collections now um i'm assuming you're following these chapters um chronologically so that you're like going one by one so i'm assuming then that you have your uh dark project set up and that you've got some sort of a simulator or emulator running so without further ado let's have a look at um i'm actually gonna bring up the captions here and then i'm gonna put my face at the bottom there and bring up our project that we created in the previous chapter up here so this this is running at the moment so if i do a command s or control s on linux and windows then as you can see here there is a run button and then it's just gonna do a hot reload which in turn calls this build function which we don't yet know really how it works because i haven't really explained it but what we did we just called a print function here and then our get full name function so what i'm going to do here is let's remove this code from the build and let's remove everything that we wrote here as well so keep the main function as you can see here and then keep your stateless widget which we're going to talk about later okay so instead go and create a new function that is called void test all right and then in the build function just say test all right just like that the purpose is that in this function we're going to write most of the code in this chapter so we are going to basically test some code that's the purpose of this function so let's talk about if and else if and l's are control statements in most programming languages that allow you to branch your code based on a condition so if we for instance in here create a final variable whose value cannot be changed if you remember from the previous chapter whose value cannot be changed after it's been assigned to let's say final name is foo all right and end it with the same semicolon now an if statement basically allows you to check the value or a condition to be of a certain value or to be true or false and then it allows you to execute some code and then you can also append an else statement to it which gets executed if the code or if that condition is not met i'm going to show you how that is written the syntax for an if statement is just if and if is an is a keyword so you would say if and then you would open and close parenthesis and then you would put curly brackets like this that's the syntax of if and in the parenthesis you would put your condition so i would say in this case if name and i would like to for instance check if name is foo now uh we haven't come to operators yet we're going to talk about operators actually soon but this is um as you can see here we're saying final name equal to foo this is kind of like um an assignment uh operation and that is an operator in dart it's called an operator so there is also and since this is an assignment we don't want to actually assign anything to name you want to check if it's of a certain value and that is with this conditional operator equal equal and then you will just say okay if it's foo then for instance print uh yes this is foo and then a semi colon to end it however if this condition is not met you may want to execute another piece of code and then you can just do else like that and then this would you would just say no this is not foo all right and a semicolon so i'm just going to do command s and you can see the value or the string yes this is food printed to the screen or to the terminal here or to the debug console you can have multiple statements in here so you can have more print statements in here you can just do anything you want basically in here and the same goes for else now there is a possibility to write if statements kind of without the curly brackets but you don't see them that often and i recommend that you actually always try to as a convention do with curly brackets if you can however it is possible that inside a code base that you will work on with your colleagues it is decided that it's okay to have if statements without curly brackets where there are very simple and one-liners basically so let me show you an example of that you could just say if name is foo you would just say print yes this is foo and this is completely accepted as well so because it's a one-liner but if you then say okay i want to have another line print hello world you can see it goes to the next line meaning that this line right here will be executed no matter your condition up there so this is completely detached from your if statement up here okay and i just realized that it is quite important for me to be able to show line numbers and by default your editor probably has line numbers enabled i usually disable line numbers when i'm working myself basically but when talking about code with other people it's quite useful to have line numbers because i can then tell you oh look at line nine or look at my line ten okay so that's the basic of if and else now you can also have if right after else so an example of that is for instance to say if name is fu and then you do some code all right you say print yes it is foo not food after the curly bracket then you would say else and then you can then say another if else if all right and then after if comes the parenthesis and a curly bracket if you remember from the if before it is the exact same syntax as it as it is here so there's pretty much no difference you can you see if and then if and then you put your condition in here you would just say if name and then you may just want to say is not and that's another operator it's uh basically is a not operator so it's checking to make sure that this name is not of the value that you provide to the right hand side and then you can say bar and print this value is not bar else and then you can wrap it up and you can say print i don't know what this is now i i'm so glad i actually accidentally ran into this issue as you can see now the editor is kind of going crazy and darts not understanding what this statement is and as we talked about it previously um strings in dart are preferred to have to be kind of like created with single quotes however if your string in itself contains a single code for instance in this case the word don't contains a single code then dart kind of gets confused like okay does the string in here you can see it's up until this point is it's a green so it's thing it's thinking that oh the string ends here but what is all of this then that follows if you have that problem there are two ways of fixing that either you scape your single code and that is a that is a software kind of development lingo escape kind of if you hear that it pretty much just means that you're um you are kind of wrapping it in a way that dart understands that you don't mean it literally you don't mean that i want to end my string here except that this needs to be escaped and put in the string as its own value basically it's kind of difficult to explain but i think you know what i mean um so that's one way of doing it it's a little bit dirty so in case you run into this issue it's best to actually wrap your entire string in double quotes and this way then dart understands that whatever comes in here is okay like a single code is completely okay unless you actually want to have a double co double uh double quotes in your string that is enclosed with double quotes again so you'll see if i put a double quote here then dart goes crazy so you can escape it with a backslash like that so if you have single codes and double quotes in your string then you will have to kind of pick a convention either you enclose the entire string in single quotes and scape your single quotes inside that string and let the double quotes live or you enclose your entire string in double quotes and then you will escape your double quotes in the string i hope i hope that makes sense so that is um if and else in um in a nutshell but before i move on i kind of want to explain an important concept here in that when dart executes this code it kind of goes by line by line so it starts with line seven the execution of this test function and then it come comes here and it says okay name is foo all right um and it's actually saying that we prefer const so let me change that to const okay so um and it says okay if name is foo all right then it comes over here but let's just change that to foo with triple o um actually yeah let's no let's not do that let's keep it as foo so it says if foo is if name is food then it says yeah that's true and then it goes here however as you can see the line number 11 also says if name is not bar then it should execute this as well and and you can see that foo is not bar so this condition is also true however this this this will never be executed and that is because when dart goes inside these curly brackets then it says okay i did what i had to do i did my print statement the rest i ignore so if an if statement is kind of like a is a it puts a stop when it when it falls into one of these if statements it kind of says okay i did my job in this entire if else block then i will execute the code after that so if i clear the console here and press command s you can see it only says yes it is foo it doesn't come here so however if you change this um condition so that the dart compiler or basically the execution of the program doesn't fall into line number 10 it will eventually fall to line number 12. so you can see it says this value is not bar so when you're writing your if statement and else statements just be careful with that just know that it's kind of like a as soon as the code jumps into one of those branches it doesn't go to the rest of the branches and checks them basically all right okay that was for if and else now let me check that in my notes that we've talked about that what we need to do now is to talk about operators operators they there are three different types of operators there are prefix operators infix operators and suffix operators and and i will explain them to you i mean how they work um i think to explain operators probably it's best that we talk about numbers so let's go in this test function and delete everything that we we've written here and let let me just say final h is 20. all right so um now we've created a variable whose value cannot be changed after spin assigned to because we created as a final a variable whose value is 20. all right now if you want to calculate half of this value how would you do that then well there is an operator for that and that is a division operator so you would just say for instance final half of age as you can see we're using camel case as i explained in the previous chapter an easy way to do camel case is to say half of it just writing in english change the first letter of of like this here change the first letter of all the words except for the first word to uppercase and then remove all the spaces that's camelcase basically so half of age is age and then there is a great operator in a dart called a division operator and then you would say all right and then you could just say print half of h so command s and that says ten all right so that's the division operator and then you will have let's say final double the h and then we will say h multiplied by two it's kind of like a star that is an operator and you can see these both operators this one the division and the multiplication uh multiplication it's a little bit difficult to say operators are in fix operators and an infix operator is an operator that has two parameters one to its right and one to its left i don't know how you can actually yeah one two one to each side i don't know if my video is like mirrored so if my right hand is actually right hand on your side as well so i don't know yes it is probably so these are infix operators when they have two values one to each side however there are also prefix operators and an example of that is for instance if i said final h minus 1 and actually we change this to var i'll explain soon why and if we said minus minus h now this is an example of a prefix operator and a prefix operator is an operator that it comes before whatever it has to do its work on and in this case this minus minus operator what it does is that it takes the value that comes after it it decreases that value by one and then it returns its result back to the left-hand side so in this case the the interpreter comes here and says okay you wanna calculate something okay it's equal to oh a prefix operator that takes a variable here and it says okay what is age is 20 minus 1 is 19. puts it in here and it also puts that minus 1 sorry puts that 19 in an h so i think so at least so if we say print age and print age minus one now both should kind of be 19 and you can see it says twice you see 2 19. so that kind of means it's uh twice so flutter has this great ability not to duplicate basically log statements or print statements so we have i mean there are some really great operators in dart and that is the plus operator operator and then you have the minus division multiplication and then you have the logical kind of like operators to check if a value from the left is equal to the value to the right so these are kind of like the basics of the operators in um dart so you don't have to know so much more about these for now i would say um you can get really far with these and a lot of these operators actually work not only on numbers but also on strings so and for instance if you this is one of the cool features of dart which i absolutely love i think it was just such a great idea for them to implement this like uh one thing i mean if you're not coming from a software development background um you may not know this but if you're coming for instance from design background also you would notice that sometimes when you're creating designs or any any screen and you want to kind of like show that design to someone like a product owner you want to actually populate the text inside your design with some lorem ipsum and lower mibsum is basically has a huge history of where it comes from but it's usually some sort of a dummy text kind of that you want to place inside your design so that you can just like display and show it to someone and a lot of developers like in many languages when they want to display some text and they don't know what to say like we're just testing stuff i just want to display some text they go and grab lorem ipsum and then put it in their code but dart has gone to the next step and said okay we don't need that so what you can do you can say for instance name is foo that's a string name but you can say name times 20 is name times 20. you can literally say multiply a string by 20 and what that does is that it says foo 20 times so if i say print name times 20 you can see it's 20 times so it's a great feature you can say foo bar pass and then just say times 100 and yeah it just that's it copies it for you 100 times in names time 100 for instance so so that is a um that is shortly said that is the basics of operators in dart okay i'm gonna delete that code i'm gonna mark in my notes that we've talked about that now i'm just gonna quickly also mention that um we can also create custom operators to be honest with you and i don't think it is completely all right right now to talk about custom operators i think it's kind of like a topic to talk about later so i actually just moved it in my notes that we don't need to talk about it right now because we have to know about a little bit about a little bit about classes and objects so that we can after we've created our own class then we can create custom operators as well so i don't think it's completely appropriate to talk about right now but just know that in the future you can also create your own operators and then like or you can also override like different operators and how they work with different objects so it's it's really fun um but that's that's that let's just let's just leave operators to that for now now the next topic that i wanted to talk about is lists and a list in dart is a series of things that are similar to each other and they are placed inside a list as you would have for instance a piece of paper and you could write your shopping list or like a christmas shopping list or whatever and it's numbered so um these are called lists in dart so for instance if you say foo and then bar and then bass as you can see dark doesn't like this syntax at the moment it says okay what are these like what is this uh uh comma here the way to tell darth that this is a list of things that are like in place one two three is by placing them inside uh square brackets and then a semicolon of course now um as i've talked about it before just just now actually lists have indexes in that they all have their own place placement inside the list and all these objects as we call them they have their placements inside the list and you may think that object number one is foo and then object number two is bar and now number three is bas and i kind of correct but index says in i mean all the programming language that i've worked with c plus c rust dart swift javascript they pretty much all start at the index of zero and that is so important to understand because like the placement of this object called foo inside this list is not one it's actually it's index is zero and that is why lists are called zero based and their indexes are called zero based indexes so you've got to be careful with that and we're going to talk about indexes soon actually so let's just say final names is that now if i want to extract foo from here i'm just going to say final foo is names at the index of zero right i'm just going to print it i'm just going to say printfu and you'll see food printed here now if i say i want to get past then i'm going to say print sorry index of three and you'll see oh sorry index of two because it's the third item but since indexes are zero base then it's in excel so i made the mistake myself so command s and you'll get bass and i actually want to go back to this three and then command s so you can see what happened here you'll see you you'll get something called a range error which is an exception an exception in dart and many other programming languages is when things go wrong so that the language doesn't really know anymore what you mean and in this case you can see this through an exception at the language level or at the library's level where it says there are no four items in this array or in this list because the index of three indicates four items item number one in the list has the index of zero item number two has the index sub one item number three has the index of two and item number four has the index of three and there are only three objects in this array or in this list so zero index zero one two so that's it and index of number three is non-existent and that is why we're getting this invalid value not in inclusive range zero to two so that's how you access items inside a list and this is how you actually create a list okay so you say list of items which is full bar bas so you can also there are some convenient um properties on lists that you can for instance say final length so if you want to know how many items are in this list you can also say names dot and then you would say linked we're going to talk a little bit about that now as well because i think it's so important to understand what that is dots in dart and in many other programming language is a way to drill in to something to extract something else from it and in this case names is a list and all lists in dart have something called properties length is the property of the list data type in dart and that means every list in dart has a property called link that is automatically calculated for you you don't have to do anything as you enter values in this list this length is gonna then return the right value to you so i'm gonna i'm just gonna talk about that a little bit more so i'm just gonna say print named length it's gonna say you'll see here let me scroll a little bit it'll say three three items in this array i'm gonna change the names list to var so that we can actually um change its contents and mutate it like i just wanna add a new name to this names and i'll just say add is a function as you can see because it has parentheses right after it so and i will say um my name and then semicolon to end the statement now if i say print names length right after the statement you guessed it oh i can see actually my um you may not see all the print statements because this text is right there so let me resize my visual studio code a little bit so you can see things a little bit better sorry about that so now we have names length here and you can see the second time around it said four okay so when you say dot after the name of a of a variable and that means it can be a constant a variable or a final variable after you put dot after its name you're accessing different properties or different functions inside that thing okay so it's kind of like an accessor it allows you to drill down inside an object and grab things out of it or maybe make that object do something for you okay so i think i think that's good enough to be honest with you about lists i don't want to go too much into details and scare people about like all the different things you can do with lists and but there there is great documentation on dart's own website all you have to do is just to google or duckduckgo or whatever you want to use bing your your way through and just search for dart arrays documentation or just dart arrays and then you will find lots of information about it or sorry dark lists because in dart they're actually called lists in some other programming languages they're called arrays but those names can be used interchangeably to be honest with you lists and arrays are kind of like yeah almost the same thing so all right um that was lists in dart i'm gonna take it in my notes so that we know we've talked about it the next topic that i wanted to talk about in this video are things called sets all right and as you can see in the caption i've written here is a list of unique things whereas lists were lists of homogeneous things sets our list of unique things so i think the best way actually to explain sets is just to jump right into it so the syntax for a set is with a curly bracket and actually i think i think it is yeah i think so so let's say final uh names and i'm just gonna say curly bracket foo and then end that okay just like that now if i type names here you will see that the suggestion provided here or the information provided by visual studio code says names is a set of string we talked about this in the previous chapter that when i say final names or final something name for instance is foo i'm kind of telling dart to create a variable whose reference name is name and its value is fu and dart automatically understand that the data type of this value is string because its data is string so you don't have to say final string name although you could do that but let's change this to const as well as and you don't have to actually say this is a string because dart understands it automatically so you just remove the data type if that's what you want to do which is what i actually prefer to do instead of being too verbose unless you have a really good reason to provide the data type anyways let's go back to sets so we were here means and that's and in the same way that we created a string and then dart automatically understood the data type by putting uh square brac sorry curly brackets here or curly braces here and putting some data inside that dart automatically understand okay this is a set of some stuff in here and this stuff for now just looks like a string so if i say foo bar as um art says okay this is fine but if i go in here and i say foo again you can see i automatically get then an error message say saying two elements in a constant so literally cannot be equal because it understands that this foo it has already repeated there okay so let's remove foo from here and let's do an experiment let's change this names to var so that we can actually change its con its contents then go to name and add to the next line and say names if i can spell and say add and then say foo again and then say names add bar and then set add bas or sorry means advanced and then we'll say print names okay and i'm gonna clear the logs with this button right here and then i'm gonna press command s and you can see that the set is still full bar bass nothing changed really there that is one of the greatest properties of lists of um sets in dart and in pretty much every other programming language that supports sets and that's sets only ensure always that their data is not duplicated and this is i mean there's lots of magic happening in the background that i haven't really talked about in i mean for instance like the question that you may ask how does dart know foo is the same as foo does it compare them yes it kind of does actually um it's internally doing a comparison between these things but we never told it how that comparison should work and that is because if you remember from operators when we talked about it the string now we haven't talked about classes well i'm just going to say strings in dart already know how they should be compared with other strings okay so they they kind of have this logic of hash codes and comparison operators that they know exactly like okay given this string am i the same as that like given sorry given what i am and this new thing that you're providing me like i'm foo and you're saying foo am i the same as foo and then it says yes or no so that is what sets are doing internally but we don't actually see that so um just know for now that sets in dart allow you to create unique lists of things okay and then you may also be a little bit like tempted to go and say okay i have things here let's say const things is equal to foo and then we say one and this will also work and that is because dark has the concept of object as well you can see you'll see things and it'll say oh now it's a set of object we haven't talked about objects yet and if i look at my notes i can see that we're going to talk about objects in chapter six and we're right now in chapter four so we haven't really gotten to that point to talk about objects and i don't want to really scare you about objects and what they actually are but just know that there is a hierarchy of data types so you have object and then you have data types that kind of derive their functionality from objects so here sits object and then here's its string integer double etc and then you have sets and blah blah blah now when you're here when you were first here and you said i have foo barbaros all strings then dart was like okay this is a set of strings but then you said oh i have a string and i have an integer which is a number now dart was like oops i have i can't i mean i don't really i can't say this is a list of strings and integers that's not possible in there so it says i'm going to take the common denominator type that sits above them as their parent to specify what these things are okay and that is kind of like the same thing that we do in real life in that if i give you for instance um uh two candies like a twix bar then you say then you would say this is a twix bar that's one thing if i give you 10 twix bars then you will say a lot of twix bars or 10 twix bars if i just give you a bunch of twix bars oh that's a bunch of twix bars but if i go and like blend like lots of twix bars mars bars whatever all the sweets into a bag and i give you that bag what do you call it you don't say oh this is a bag of twix and uh snickers and this is a and mars bar no you would probably just say candy it's a bag of candies and that's what dart is doing here saying oh you threw a lot of stuff in here i i can't like comprehend that this is a set of uh objects so we do that in real real life and that's what dart is doing here so just when you see object just know that oh dark doesn't really know what this is anymore so or it kind of knows what it is it's just a bunch of stuff so that's what object in this case means so that was a weird uh comparison maybe but i hope you get uh what i mean and if you see me looking here it's just because i'm looking at my notes to ensure that i've explained the things that i've set out to explain so talked a little about about hash codes and sets we don't have to go into details about that so now let's go and talk a little bit about maps um and maps are kind of one of my favorite data data structures in any programming language that supports them pretty much almost all modern programming languages support maps so a map is a data structure as you can see here maps are used to hold key value pairs of information and what that means is um let's say that you want to explain a person using their different properties then you would say age their gender their hair color their heights uh whatever name all that so these are kind of like your keys so you would explain the properties of that person using those keys and all those keys have their values so if you say height then you say like 180 yes and if you say weight then you select 70 kilograms so these are key values the keys are the properties of that person and the values are the values of those properties so and the way to create a map is very similar so to very similar to a set with a curly with curly brackets so you say person and then you say equal to actually this is just a name you don't have to say person but yeah or you can just say const so person and then you open curly brackets and then you would do your keys here and i would say the key of age for instance i'll say 20 and then you say column is it calling yeah it's a column and then you end the whole set with a semicolon so i just created a basically here i created a map whose keys are string and values are integers now let's see if dart understands that you see this is it's a map of string as keys and means as values but now as you saw before the analogy of candies now if i say okay i have another key and it says um name and i say oh the name is foo dart's going to be like oop what is this person oh it's a map of string as keys and object as the value because it just looks at the common denominator of the string which is foo and 20 which is an integer and says oh i don't know i can't create a map whose keys are string and its values are both string and integers so i'm just going to go to their parent and be like oh the parent of both string and integer is object so your values are of type object so a bunch of candies basically okay um that's how you create a um you create a map in dart so and the other property of a map is for instance you would say um if you if you go and create an agent again here you see it says two keys and a constant map literal cannot be equal so it's doing some checks here making sure that the keys are actually unique so keys inside a map need to be unique all right so however if you go and change this and say var person so and then you later go and say person name is equal to foo like just like that and then you print the entire person so i'm just gonna say print before and print after okay and you can see here it said first time h key is 20 it has a value of 20 and the name k has the value of foo with a capital f then the second time around on the print statement on line 15 then we when we print the person it has the um key of age with a value of 20 because we didn't modify that and a key of name as it was before with the value of foo with like six i think uh capital o's so this is how you would modify a map you would specify the key and then you would say equal to which is an operator and then you would say the new value all right um however if you added a new key here for instance um last name and you say bad and that will just kind of like get appended to the um to the map so age the same name the same now you have a new key whose value is bas all right and that is kind of like the basics of um maps so there are lots of things you can do with maps and i really encourage you just like everything else that i talked about in this chapter that you go and read some of the documentations because if you're following along with this course and your goal is to become a software engineer and if you're for instance a project manager or a designer ux or whoever you are um i think you need to understand that software engineers do not know all the answers you have to go and read documentation you have to practice practice practice and put time into it countless countless hours you need to put into learning so i i mean this course i think is going to be so many hours long the the way i can i mean i can see uh the planning for all the chapters that i put here there's so many chapters i think the entirety of this course is gonna go over 20 hours so you can imagine i can't go into details about every single thing otherwise it is just this course is probably going to be like 200 300 hours uh it's unbelievable so we can't do that so what i expect you to do now is just to open your browser and just type dart maps documentation something like that dart maps so and you also need to know that now that you're starting to google things you need to be aware of the word dart and that dart is an existing very popular name for just darts darts okay so sometimes depending on what you're googling if a topic related to the classic darts that you throw is more popular than the topic of the programming programming language which kind of sounds the same it may pop up first so in this case if you say dart map you may actually end up in some sort of weird website that explains to you how you can throw darts at a map i don't know i'm just trying i'm just trying to bring it up because that i actually ended up in that situation that i searched for something related to dark i actually ended up in a weird website talking about darts as like a sport so know that as well please all right now we've uh talked about maps so i'm gonna take that in my notes um now what's coming in the next chapter we are gonna talk about a very um important concept in dart and many other programming languages such as rust and swift and that is null safety or dart calls it sound the sound noise safety it is a very important thing to know about in dart and it will greatly help you in the future as you write your flutter applications and in this course i'm going to use a lot of um null i'm going to make a lot of null references talk about null quite a lot throughout the course so it is very important that we go through that as soon as possible and we're definitely not gonna leave that out so that's gonna be for chapter five so keep an eye out for chapter five that is to follow so i hope that you enjoyed this chapter chapter number four where we talked about dark control statements and collections and i'll see you in the next chapter hello everyone and welcome to chapter number five of this vlogtech course in this chapter we're going to talk about null safety um in the previous chapter chapter number four we talked about dart control statements and collections and before we go on to talk about enumerations and objects and classes i feel it is very important to talk about null safety which is a concept that is available in most most modern languages such as dart sorry such as rust and swift so it is important to kind of like get this out the way before we continue maybe not even get it out of the way but actually like learn what it means and try to utilize it so that we can write better code so um i thought to just bring up um the concept of null values and why they're important to handle well i mean you've seen so far that we have data types a data type can be for instance a string can be an integer and then you can put values in them um however in programming languages you're also allowed to have the concept of the absence of a value so on one hand you have values so you for instance have a string value equal to foo bar or your name or whatever it is and then on the other hand you can have the absence of that value so you can see that okay i have a container i have a variable that can contain the values of type string or i have a variable that can contain any object however at the moment i don't have that value so you will just tell dart that this variable that i have right now that can either contain a valid value of type object or of type string or integer or it can sometimes also during its lifetime contain nothing and this nothingness is the concept that is known as null um so it's null in dart is a keyword um it means that it's a word that you can just write in your text editor as you're writing your code and you say that a variable's value is equal to null and this tells dart that well okay this variable at the moment doesn't contain any values so null is not really a value but it's actually the absence of a value you should think of it that way so let's have a look at this um there's a little bit of a documentation here um uh on dart's website dart dev null safety so i'm just going to click on it you're not going to see my screen at the moment i'm just bringing it up in a browser a browser window i'm going to bring it on the screen and increase the size a little bit and also change the sizing on the window as well so you can see the contents in its entirety um so as you can see in dart it's called sound null null safety and there's documentation about what this actually means um we're gonna look at uh [Music] look at what's not safety actually means in dart and i'm gonna give you a lot of examples of what that actually practically means and there's documentation here in dart's website simple simply because dart um in its older versions and not in its current versions it in its older versions it didn't support uh all safety so there was a lot of code written manually by programmers in order to for instance check whether a value is absent in a variable and then there is as you can see here it says migrating an existing package or app so there is documentation written by the dart team in order to help developers understand how they can move their old code to the new code that supports null safety um however if you're following along with this course and you're it's like you're basically just following chronologically from chapter one to all the other chapters i don't know how many chapters were going to happen if you're following along with this course you don't have to think about migrating because the code that we're writing in this entire course is going to be null safe meaning that we're going to take advantage of darts null safety operators and meaning that we are not going to manually check for values being null and then doing some branches of code whether they're null or not but so what i mean is that if you read the documentation for sound safety you don't have to worry about the migration parts just read the rest okay so with that out the way i'm just gonna make sure that i take that in my notes here that's why i'm looking in this direction because i have all my notes here um let's close this window and bring up our visual studio code window that we had from earlier i'm gonna put it here and i'm just gonna ensure that it is of the correct height as well so you're gonna see it the window in its entirety okay so now that we talked about what non-values are and that they're the absence of a value let's have a look at making any type nullable and if you follow along with the with the course up to this point you should have some sort of a simulator or an emulator running and then you should have done command shift p or control shift p uh depending on your operating system command shift p in mac and ctrl shift p in linux and windows in order to bring up the um this menu and then you can just type flutter select device and then you just select the device that you want to run the code out so i'm kind of assuming that you've already done that and that your code is running and this is something that we talked about in earlier chapters so we're not going to go through that again so i have a an iphone simulator which you cannot see on the screen but i have it running in a separate uh screen just because we don't have enough real estate i can bring it up to this window but it will just take a lot of space so i'm gonna bring it up to another monitor so you don't see it so this code at the moment is running live so if i press command s then it's gonna run and just print the output for us okay um now let's talk about making any type um nullable and there is a way to do that let's let's have a look here we talked about that null is a keyword and that that's why you can see it is like um highlighted here in a different color so if you for instance say final name is foo all right as you can see it says okay i accept this as his name is foo but you can't just say name like it's a null because then it doesn't understand is it an object is it's a string is it nil right is it an integer and if you type here name then you see it's just dynamic it doesn't understand the type so and we'll talk about dynamic a little bit later um but what you can do is to actually specify that okay i want a string data type that it can contain normal names or strings as we call it like series of characters or it can sometimes be null and in that case you have to actually specify the data type as um not just string not just this because you'll see you'll get an error and you'll actually get a suggestion it says try changing the type of the variable or casting the right hand type to string but we're not going to do that wasn't it such a it wasn't such a useful suggestion because what you want here is to actually make dart understand that this variable right here or this constant right here can sometimes contain the value of null and the way to do that is you put a suffix after your data type as a question mark so this is this is the syntax which is actually used in some other languages as well it's used in swift as well so um this tells dart that well here if we make it actually variable as you can see or sorry like this so you say i have a variable it's it's a string but sometimes it may the string value may be absent um and then you'll just say okay now name is foo and you can say now name is no so this is kind of like resetting out names so if i just say okay print name and then after foo i say print name okay so let's just clear the console and just run this application you can see the first time it says it's null and then the second time around it says it is foo so this is how you tell dark that you want to have nullable data type and you can do this with pretty much all data types so you can just say okay i have an integer um of age and that's 20. but you can see you cannot now assign the value of null to integer because it's not nullable but as soon as you make it nullable then that is accepted so um and of course you can do um you can do different operations using for instance we in the previous chapter i believe we talked about control statements if and else so you can say for instance if age is 20 and then you can encode or you can say if age is null execute some code so they work as you would expect so there is no difference really and i mean if you if you think about that notability nullability is just like a suffix to a data type you can also say okay pretty much any data type can be nullable and that's that's correct like for instance if you have a list of string of names and you can say okay i have foo and bar here this is a list of strings i've talked about lists in chapter four now you can you can see here that list of strings there are two data types here the list itself and the contents that it holds so if you want to make the list in itself nullable then you would put the question mark after okay this means this list of strings in itself can be absent so you say name is null and that's accepted all right however since you're telling dart that okay the names uh value here can its entirety be null but its values are not supposed to be null so if you then go in here and just put null in here then you see that you got an error and that's because dart is saying that okay you just promised me that the list in itself it can be absent but as soon as it is not absent meaning that as soon as it is present there with some values it's the values cannot be no and that means that the this type should be you're telling me here that it is not so if you want to make an optional or nullable list of optional strings then you would put the question mark after the data type of string as well so this is now i mean the way you should read this is i have a list of strings and i call that list names names can sometimes be no meaning that it can be absent and if it is not absent it can contain objects of type string that themselves can sometimes be absent meaning that okay like for instance if you say fu bar no that's accepted but you can also say names is no see what i mean so both the container which is called names and the values that it contains can be optional and the word optional is very important for you to learn it's it's kind of like an industry accepted way of talking about nulls and nullable values so this is optional all right okay um now we talked about that nullable values and optional values all right basically you can use those words interchangeably so if you're talking with a colleague programmer you would say oh how would you describe this okay this is an optional list of optional strings or you could also say nullable list of nullable strings but optional is also word that is typically used to talk about nullable values all right okay we talked about making any type nullable so um i'm just gonna mark that as done that we've talked about it in notes all right now let's talk about cherry picking non-null values and what this means is with dart you can easily ask the language to give you values that are not null at all i'll explain what this actually means let's say that you have a um you have a string final um string first name and is equal to foo okay now let's just say this is a constant all right that's that's what the suggestion was you see i wrote final because i was not planning to reassign this first name value to anything else but then i got a suggestion to actually use the word final here or the keyword final sorry the keyword comms as you can see here so let's say const all right um now what we want to do here then is to also create a last name or middle name r and then we say last name and actually what we're going to do is we're going to say the first the first name is null all right so first name middle made bar and last name bass now if you want to if you have these values and you want to for instance i mean right now you can actually see the values that you put here but sometimes these values are passed to your function so you don't know what they are right now you can see what they are so it's easy if i told you pick the first non-null value then you would say middle name because you can see it however if you had a function for instance test here that accepted those values for instance string first name string last name and then string or yeah middle name etc then you wouldn't know what those values are or you cannot make an assumption about what those values are except that they are nullable or optional strings so i hope that you get what i'm trying to say now if someone told you to pick the first non-null value one way to do that is like the old way of doing that is to say for um if first name is not snow um then you would say oh i again okay i know first name is the first non small value okay and then you say okay if first name isn't null then we pick it otherwise else if middle name is not null okay and then you say okay middle name is the first nominal value and then else if again so last name is not null then you would print the same thing so this is very repetitive um and it's basically um so it is basically very verbose in the in the way it is created there is a better way of doing this and that is with the uh question mark question mark operator in dart which is available in some other programming languages such as swift as well so the way to do that then is you would want to pick the first non-null value so you would say final or const first non-null value and you would say that's equal to first name or or so this is kind of like question mark question mark middle name and then question mark question mark last name so and i mean we're getting a warning here just because dark understands already that this middle name although a so it's this is although an optional basically it has a value but if we make this null so and that warning goes away but i mean it would probably be cleaner if we actually pass these as parameters into this function so we don't get these weird warnings but the way the question mark question mark operator is working is that it says it is an infix operator just so you know in in from chapter four you know an infix operator is an operator that has two things and one on each on each side the right and left so in this case on the right side we have middle name and on the left side we have first name so what this operator does it says if the value on my left side is null i'm gonna pick the value on my right okay and let's now in this case say okay middle name is not now so what it does it says first name or you null yeah you're not then i'm gonna go to the right side middle name are you no no i'm not no then it's gonna pick that and the rest of the statement is not gonna be executed however if middle name was also known in this case then what happens is that it begins from the left is a first name or you know yes middle name or you know yes so this entire operation here it doesn't yield any value and then so this entire operation will let me know so it says okay now i have to compare our left left hand side are you know yeah we know that this entire thing was no and then it says right hand side are you null nope i'm bass then it takes pass so the this question mark question mark operator is a null aware operator that picks either the left side or the right side whichever one is not null first in that order so left side are you null if you're null i go to the right side but if you're not not not null i'll pick you so keep that in mind it is a very handy operator and it will shorten your code quite a lot all right now if we then go in here and say first non-null value you can see it actually says oh it's a string however if we if these were parameters so if we said first name and then string last name sorry middle name last name they were not provided to us like that converter was okay and then we say final now if we say first non-null value in this case since it is a normal case excuse me where the dart compiler isn't working with constants and then it cannot resolve this to a constant value at the moment so it says okay there are three optional values i have no idea what they are so i'm gonna do my best to pick the first nominal value depending on i mean based on what we provided here however i may not be able to solve this so the final result here as you'll see is and it's an optional string meaning that well i may not be able to resolve this meaning that this entire operation on top on line 9 may result in a null all right sorry about that sorry about my voice so that is the question mark question mark operator so i'm just gonna mark that that we talked about it in my notes okay so that was that um now let's talk about the next topic uh which is the null aware assignment operator i think that's that's this actual official name um this operator is very similar to the question mark question mark operator in that it it tries to resolve a variable to make sure it is not null it's going to do its best um and let's have a look at an example let's just say um bar and i'm gonna say actually let's just say ring and name is first name so we begin we say that we have an optional name and we begin by assigning first name to it so it means that this name might at the moment depending on the value of first name it may be null and now if that is null you may want to assign another value to it all right and then you can do that with this operator you would say last name let's see what happened here both trying to oh is it this yes it is equal to so i actually should change this case to equal to question mark yes and i'm going to bring it up again so that it is actually correct let's say and then name equal to isn't this working lastly oh dummy where was it this one try changing the it like this i'm actually a bit unsure right now so let's have a look actually what this does um and it's three positional and then we say no no no and then bar and then baz here okay so first name is null middle name is bar and last name is bass and to be honest with you i mean this is quite a lot for me as well it is something that is like the syntax of the programming language it is something that you will kind of need to live with you're not gonna memorize this all just in in your head all the time of course like the main parts of it you're gonna you're gonna remember but uh not all of it so and you can see for me as well i'm just like at the moment okay which one is it um so i'm gonna test that so i'm to begin with we say name is first name and if that is null then assign actually let's just say middle name name here then use middle name and then print the name finally and i can see it says bar here so it's actually question mark question mark equal um so i actually maybe need to edit this text one more time so i'm just going to say question mark question mark equal bring it up because i think question mark equal is not going to work an equal question mark isn't going to work either it's not a value it's not a valid syntax a question mark question mark equals sorry about that so what this operator at the moment is doing it says that i'm gonna take the value on the left hand side and check whether it is null or not if it is null then i'm gonna assign the value on the right hand side to the left hand side if it is not null i'm gonna leave it alone okay so at the moment first name as you saw here is null the first parameter that we passed here so what it says it says okay i'm going to check then for middle name if if name is null and it is null and then it says okay middle name are you like presenter and i will assign that value here so it will be um [Music] basically it will be bar which is the value of the milling now if we in here said middle name is also null right we could have another operator here that says okay if after taking the middle name we are still null then take the last name so and you can see bass gets printed to the screen and that is because because bass is the last parameter that we're checking on line 10 and its value is not null um so you can see how like if i then went here and actually said the first name is bar then you will see that that will be the value that gets printed to the screen here because right here name or first name which is bar got assigned to name so it is an optional string but it has a value which is bar then when you come to this line number nine then you're telling dart look if name is null then assign middle name to it and dart says well name isn't null it is bar so i'm not going to assign middle name to it and then it goes to line number 10 and does the exact same thing all right so that is like the null aware assignment operators and uh it is useful i personally i mean to be honest with you i as you could as you could kind of guess i don't use this operator so often it is there and i have no shame in saying that pretty much in none of my programs have i had to use this so it is present for you to use it is available if you want to use it so just don't be like me but try to remember the syntax this question mark question mark equal okay and i'm gonna actually fix that in my notes as well that it is question mark question mark equal okay and i'm going to check it in the notes that we've talked about it now let's talk a little about a little bit about conditional method or property access or conditional invocation now as we talked about in the previous chapter with dart as like many other programming languages you can use the dot syntax in order to access or drill down inside properties and methods or functions inside other objects as we saw for instance with the case of or lists in dart you can say i have a list and then you want to get its length then you would say the name of the list dot links and that drills down inside that list and gets the links property okay however as you saw also earlier in this chapter in chapter number five even lists or pretty much any data type in dart can also be nullable so how do you access properties of a null object so let's have a look at that now let's say i'm gonna i'm gonna actually delete these properties uh the parameters that come here to our function and i'm to say and i'm going to go down here and remove these parameters as well and in here let's just create an optional list of strings not optional list of optional strings but at just an optional list of valid strings okay so i'm just going to say list of strings as an option i'm sorry an optional list and i'm just going to say means and that is equal to let's just say at the moment foo all right now in here if you try to say final length of names or number of names is names links okay if you then look at the data type here i mean we could actually say this is null okay and you can see here dart actually is allowed to or is able to give you an error knowing that this list it is null at the moment however if you accept it i think it's actually better that we accept this value as a parameter so that dart analyzer cannot be too smart about like making assumptions about what this actually is at the moment so you can see the analyzer is telling you it cannot be unconditionally accessed because the receiver can be null and that means yeah exactly as it says it says names can mean all i don't know if it's not right now or not but it can be so how do you access that one way to do that like the old way of doing that is to say if names is not null then length is named length okay uh final length is uh in x okay so that tells dart that look i'm actually checking for null values um or i'm checking that this list is not null on line eight and if it is not null then i would access its length property and this is kind of it's called type promotion and type as in data type so in this case you can see on line number eight or now if i go and create a new line on number online number eight and i say names this is an optional list that can contain strings and in here you can see it is um it is typed as the same but it is promoted to not being null because you've already checked for it because if you remove these lines of code you can see now that you get an error the exact same line but if you check first for null and you don't get the error it's a type promotion okay so this is kind of like the old way of doing that um so let's say that you want to have you want to extract the length so you say final length or means length right you create the variable but you don't assign anything to it when you say if names is not null then the length is equal to name's length otherwise length is zero okay so this is one way of doing that is the old way of doing that and you may be trying to be smart as well and say okay i don't need this else statement if i just say this is a variable and by default is zero and yeah you would be right because length is zero by default and then if names is not null then you say okay length is equal to names length however there's a better way of doing that and that is using the quest dot question mark i believe or the question mark that actually it is yeah operator which conditionally executes or invokes a method or a property inside an optional if that optional value is present i'm going to show you how to do that so if we say final links is names and then you would put question mark dot and then you would say links and you would see this this code like being executed without a problem however if you go here you would see that length is an optional value it's an optional integer so you may be like okay how do i solve that how do i say that i want length to be zero if this length value is null meaning that if it's names if the names list is null and we can't extract the length then i want this value to be set to null and that is using our question mark question mark operator that we talked about the null aware operator that we talked about earlier the infix operator so you could just do this you would say length is if the names list is present meaning that its value is not null then grab its length otherwise take the value of 0 and assign it to length and if you go to line number nine now and i say length so you can see it's an integer so it's not um is not an optional integer anymore so you could do the same thing as well like you could say names and you could do the same thing with properties and you could also do it for functions so you can say names add as right so you see this is a function called add and then we're adding the value of bass to that list however you can't unconditionally invoke this function on an optional value because it might be null all right so that is like a very very important bit of learning about dark learning about optionals in dart how you could use nullable values and as you will see and we'll talk about it more in this course um there is many cases where you have to um take into consideration all values and especially if you're working with different libraries where the library cannot make too many assumptions and your code is dependent on the library and you will have to take into consideration okay the absence of a value means that i personally have to like take some um decisions in my code consciously in order to execute bits and pieces of code depending on the absence or presence of the value so try to use these optional um null aware operators that i taught you here which was um the null aware um basically like the decision making on to pick like the infix operator that tells you whether the left hand side or the right hand side depending on which one is not null first it picks that one okay that offer is very important and the um all over invocation operator which is here so you say some object which may be null then do something on it or the operator which is a null aware assignment operator that assigns the value on the right to the variable on the left should the variable on the left be null all right so these are very very important to understand okay um now that we've talked about that i'm gonna take that in my notes that that is a topic we talked about now we also have um very very good official documentation about null safety in dart so i'm gonna bring up this documentation on a separator separate screen and then i'm gonna bring it up here so you can actually see as well all right um you can see here it says understanding all safety and this is great great documentation about how null safety in dart works as you can see a lot of examples um i mean it talks about like from the absolute beginning what it actually means uh and you can see here null is at the level of object so it's not novel itself is not like an object so you have lists and doubles and integers here but null sits on top for itself it's kind of like the absence of a value so there's lots of examples in in this link and i highly encourage you to have a look at it some things you may not understand for instance like this one you will understand easily because it says there is something called a thing like a class but we haven't talked about classes yet and its name parameter name here in this function called showgizmo is called thing and you can see it is conditionally accessing a property on that thing so and then if that property in itself is null it conditionally access that as well so if this property is nullable and then it's accessing another property inside that nullable property if it's not null so it's i mean it's a great way you can chain them as you can see here so then so if this thing is not null then conditionally accesses this property on that so it's it's beautiful i mean and this thing is available on many other languages like rust and swift as well so it's nothing new it but it is kind of like uh such an important topic to understand in dart that i think you shouldn't just skim over it so you should just really learn how to work with it so all right um we've now talked about null value so i'm going to take that in our in my notes here now i think for chapter 5 five this information is enough so that we can move on to the next chapter and in the next chapter chapter number six we're going to talk about some really really juicy stuff and this is like chapter six is going to be like um as i can see my notes are pressing in a lot of really interesting topics such as enumerations classes objects custom operators constructors factory constructors class methods i mean inheritance and stop classing apps subclassing abstract classes so as you may have heard depending on what background you have you may be like a product owner or product designer a ux or whatever you may not have like a software engineering background but dart is um in its core it's an object-oriented programming language it means that things in dart are objects an object is an instance of a class as we'll talk about in the next chapter so um for you to understand dart and how these things work for instance we've talked about lists and actually typing dots in front of the name of the list and getting its lengths but you may not really know how that works so in order to understand all those things what that dot means you need to understand what objects are in order to understand objects you need to know what classes are and when you understand classes then you will learn about inheritance and then you will talk we'll talk about abstract classes properties static functions all that so what we're going to talk about in chapter six is so important that i believe that every dart developer needs to know about this and we're learning all of these things to be become good at doing flutter um so uh although you can go and write like servers or maybe server applications with dart or you could write command line applications with dart but these days dart is primarily used for writing flutter applications and i don't have any data to prove that but i can see for myself when i'm in the community that most people are using dart primarily to write flutter applications so we're doing all of this to learn more about flutter and i highly recommend that you don't skip these chapters where we're talking about art especially if you're new to flutter development so with that said let's leave this chapter the way it is right now chapter number five we're done with that let's go to chapter number six and learn about dart enumerations and objects welcome to chapter six of this flutter course in this chapter we're going to talk about uh dart enumerations and objects and these are some of my favorite things to actually talk about so um in most programming languages actually have the same facilities so if you follow along with the other chapters then you should have a working dart project set up now and maybe running in an emulator or a simulator so that you have the ability to press command s on mac or control s in linux and windows in order to rerun your project so without you having to pretty much do anything so let's then get started i'm just going to make that assumption that you're already set with those requirements so let's start by talking about enumerations and i'm gonna bring up the project from the previous chapter let's just make sure that it's on the screen so you can easily see it now i'm going to go and to this list function that we created remove the only parameter there and remove that as well so if i press command s now nothing should happen on the screen because we don't have any functionality in tests so let's talk about enumerations and what they actually are as you can see here animations are named list of related items now an enumeration is kind of like equivalent of making a string written programmatically so that it becomes an entity and by that i mean that let's say you have the value name and then you could say foo and you would also say khan's other name that's also foo they're both the same string but they're not the same identity in that i mean internally actually in terms of const i don't want to go too much into the comp how the compiler actually works but they're going to be going to be the same string but i mean that you've written it twice so it's not the exact same thing you have to write it twice so an enumeration try to tries to basically make sure that a value has a name that can be programmatically referred to so let's say um cons sorry enum and that's a key word in dart that's how you create an enumeration um i'm going to take this that we've talked about some some other things during the intro sorry about i have to look at my notes anyway anyways so we have the enum here that's how you create an animation in guards and you would and then give a name to your innovation and unlike variables and constants that they're written with camel case you'd have to basically use another casing here which is the first letter of every word in your iterations name has to be uppercase and the and the rest of the letters have to be lowercase so let's in this case for instance say person properties okay the properties of any person then in this enum you will write the different properties for instance first name and lastly page so what that basically means is that you've now defined a list of related things such as first name last name age which are categorized under a particular name which in this case person properties okay and you can refer to these in your code using the dot notation so you can say person properties first name okay and we can print it actually so i'm just gonna press command s and you can see it being printed to the screen so um i mean immersions are really really great as we go on in the in learning about dart and how dart works how we can work with flutter how we can parse data that comes back from a a server for instance but for now it's enough for you to understand that you can categorize related items under an enumeration so that you can refer to them later okay and indoor you can also get the string representation of these uh values using their name property that is something that's created for you by default so if you just say name you now see first name being printed to the screen as a string but before that if you print the innovations value here for first name it would print out the entire thing okay so that's short and sweet about enumerations we're gonna use them quite a lot actually especially later where we go to more advanced topics as we develop our real application but for now just know that this is how you create an information using an enum keyword and then the rest of the properties you just put in curly brackets okay so that's for enumerations um now we need to talk about switch statements and actually let's bring this back and i'm gonna change this to properties let's say okay and let's just say for instance animal type and let's say cat um dog and then let's say rabbit maybe so let's say we have an animal type enumeration and um we want to and then we for instance get in our function we say animal type animal type so there's a property that we expect to be passed our function called animal type and then we name that property animal type with kennel casing here okay so if we do that then we go to our function here we're recalling the function you can see that we got an error meaning that there is a parameter expected of type animal type and no one's passing them so at the call side which is the place you are calling your function that's what a call site is known as in programming so if you're coming from a background of design or um anything that is not software development related so you wouldn't probably know so much about the this kind of lingo but a call site is where you're calling a function so at this call site online number 19 um we're gonna gonna pass an animal type and let's just say uh cat in this case okay so in here we could just print that and i'm just gonna say animal type i'm gonna press command s and you can see cat being printed here okay now if you want to execute different types of code depending on this animal type then you could you could which is not recommended you could use an if statement so if you just said if animal type is equal to animal type cat you say print all i left oh i love cats okay else if animal type is animal and you would say prince or or you would say dogs are so fluffy or something and else if animal type is animal type me and say i wish i had so this is using normal if statements you say if animal type is cat then blah blah blah now it is one way of doing it but it's not the recommended way of working with enumerations and the recommended way of working with enumeration especially if you're doing like branching code as we're doing here is using a switch statement so let's convert this code to switch um so let's say switch you put parenthesis open close and then open close curly brackets and in here you would put your narration so you say animal type okay and the way to handle these different branches then is with the case uh keyword you'd say in the case of animal type money print uh money sound like this okay case animal type a cat print cat and case animal type og print dog just like that okay now this is i'm great i'm actually grateful that we're getting this uh error so you can clearly see what it says is the case should not complete normally try adding break or return now what this is saying that you see in many programming languages just like dark when the program comes here to the case statement it kind of like falls through to the next line and dart tries to avoid that so it says okay if i handle bunny then i'm doing some stuff but it kind of feels like i'm like falling down to the next line after this because you didn't tell me what to do after the print statement so you either tell me to like completely go out of this function go out of the test function by putting the return keyword here we haven't talked about return really yet but you could do that you could just say okay return right after all of these so i'm just going to press command s and you will see cat being printed to screen which is here okay but if you didn't have this return statement statement here you would get an error okay so you either say return or you would use the break keyword now there's a difference between these let's put a print statement here and i'm going to say function is finished okay so i'm kind of expecting that by executing our our code here our test function here passing the value of cat at the moment that we fall into the switch we check that this is cat and then print the cat and then we return okay this is kind of what it is doing it means that it kind of skips over this print statement and you'll see soon if i say command s it will just say cat and then we'll return from that so this is not really what i wanted i wanted this switch statement to be executed print cat and then continue after switch okay and that's where you use the break statement so or the key word here so if you say break it breaks out of the switch statement and then continues with the rest of the function as it as you would expect so if i press command s here you say cat and then function is finished all right so switch is the preferred way of working with um enumerations especially if you're doing branches so you could also like um for instance if in this case he said uh pray make sure this is is a cat you could also in this case say if animal type is not animal type chats and you would return okay you could do this as well so this is kind of like a conditional statement that you're putting in the beginning of your function making making sure that any code executed after line 10 is completely sure that the animal type is a cat okay so in that case you may just use a typical if statement so you don't have to do switches okay but if you're trying to execute spec special pieces of code depending on which value this enumeration contains at the moment then i highly suggest that you use switch statement instead of if statement all right so kind of depends on your on your use case all right okay i'm just going to mark this item as done in my notes now let's talk about classes all right which is one of my favorite topics to talk about actually um well classes in uh dart and in many other languages let's actually bring this back to how it was before make it a test function all right and remove the animal type from here and remove them i can actually continue and we can actually as well okay so classes in dart are are grouping of various functionalities into one packageable piece of data and and by that i mean for instance let's say that you have a function called run another function called breathe and then you have a person's first name a person's last name of course you could go and define these things like this you could say khan's first name yeah something and khan's last name is something like this okay um just like that and then you could have a function and sorry you would say run um and then you'd have another function called breathe you can do that but these are functions that are kind of like for us in this particular case or at least in my head at the moment i'm imagining these functions to be related to a person and that person can run that person can breathe that person has a first name and last name so the grouping of these related things is done with a class in dart at least so the way to do that is you would say for instance class which is a keyword in dart let's say the name of the class now for the naming of classes and enumerations and any other entity except for variables and constants you should use um just normal casing you would i don't actually know if it's called pascal casing or i think so um but you would just use your upper case the first letter of every word okay so let's just say person okay this is how you would say a person class all right so i don't think actually we can put const in there i'm just gonna grab these two functions and just place them inside this person class all right and let's in this say print running run function and with reading we're going to say breathing all right and in the test function you would want to create something called an instance of this class now instances are objects and objects are created from classes so you need to understand how instantiation works in software development and this is for any programming language such as dart rust swift python javascript where they allow you to create classes and now that you know what a class is in order to use a class you need to usually create something called an instance of that class that means that you tell the programming language that okay here is the class i know about that but give me a copy of it so every class can be instantiated meaning that the dart compiler will create a copy of that exact class with its data its functions its properties and give that copy to you all right so that is called instantiation and it works by using the equal sign and creating putting a parenthesis at the end of the name of the class as i'll show you here so let's just say final and we say person which is the name of our variable in this case is equal to as i said equal sign then we would write the name of the class and parenthesis just like that okay so now you said a person variable in this case is an instance of that person class now you'll understand using dots and notation you could say person.run you see that function is now available on your instance of the person class and you would say person dot breathe okay so these are functions that are available at instance level of the person class i know there's a lot of words that i'm just talking about but i think you understand the point here so this is how you instantiate the person class and this is how you invoke various functions on that class so if i press command s you can see it says running and if you said in this case person and then without instantiating using their parenthesis if you said breathe you will get an error here instance member breathe can't be accessed using static axis okay and that's i mean that is kind of like instance member is an important term also to remember an instance member means some functionality that is only available at the instance level meaning that it's not available at the person class level but you have to make a copy of person in order to be able to access that all right so that's the basic of classes you can do a lot with classes as we will talk about soon so i'm just going to leave that person class right there and then just going to mark that as talked about in my notes as well and let's now talk a little bit a little bit about objects well objects are actually quite easy to explain an object is an instance of a class so you wouldn't like when someone says oh here's an object of type string it means literally that there is a class called string i've created an instance of it and and that is an object so the word instance the words instance and object are usually used interchangeably uh but if you hear someone say instantiate a class then you would say okay what's the class name oh it's person all right and person is now i created an instance okay and in this case you can see i'm just creating an instance of person without actually doing anything with it so that's got kind of like a useless object all right but if i put i say foo as a person then this foo now is an object of type of person and actually you can write its name here and you'll see that it tells you that this is a person okay so that in short is what um objects are and i can see my notes that objects need are kind of like in the wrong place i'm gonna bring it to the right place sorry about that um okay now let's talk a little bit about um constructors and i can see constructors also at the wrong place in my notes so i'm going to bring those also to the right place okay sorry about that um now what a constructor is at its name as its name indicates is a special logic in a class that constructs or initializes or builds that class's instance all right so you may say that okay let's go to our function here as to our class here person and let's say every person has a first name or name okay so let's just define that we say final string name all right as you can see now dart is saying okay you said that every person has a name but and it's a final meaning that after the person has been instantiated or after that person has been initialized or created an instance from you cannot change that name because you said final all right if you said like string name is foo that would be different because it means every person instance that gets created has the default value foo for its name that's a completely different way of saying uh what the name of in this case as you can see we're saying that there every person instance every person copy that we create has a name now dart to say okay where is the name then you didn't tell me how to create it and that's where you would want to use something called constructor okay constructors are sometimes you uh called as initializers depending on the background of the programmer they may call it constructor initializer uh or maybe some other names that i don't know about but if you if you hear that a constructor then you will now know what i'm talking about soon actually so now what you can do at least in visual studio code when you get this error is to just hover hover over it and then press command on mac or control on windows on linux and press dot now you will see you will get some suggestions here and it will the second suggestion at least for me here says create constructor for final fields okay and i can just press that and what happens here now you see it's that it creates something that looks kind of like a function but it doesn't have a name its name is implicitly set to the name of the class okay so basically it says i'm a special function with the same name as the class and i expect a value to be given to me which i will then in turn assign to the name property of myself it's kind of like a strange way of doing things but it is quiet clean as well okay after you do that so this is how you create a constructor after you do that then at the call site where you're calling this person class to create an instance of it it will complain saying that oh i'm expecting an argument but i didn't find any and that's where you have to pass the name so let's say in this case is foo bar okay and then on the next line you can just say print foo name all right and press command s and then you can see foo bar being printed to the screen so that is like the basic of a constructor that's how you construct instances of your class all right now you may be saying that all right i don't want i mean you can do many fancy things with constructors you could say okay this name for instance by default must have a special value you could do that there's lots of things you can do with constructors which i'm not going to go into the details of but right now just know that a constructor is this special kind of function that has the same name as the name of the class and then parenthesis and then you put your values in here all right okay that was constructors um now let's talk a little bit about um methods all right and what methods are i'm actually going to go here and say we're going to talk about methods and those at the wrong place in my notes as well sorry about that a method of a class we've talked about already to be honest with you and a method of a class is um a function on the class which is usually referred to as an instance method meaning that the function is available after you've instantiated that class all right as we're doing in line number 14. name is an instance variable so is a variable that is available at an instance level is not an instance method an instance method should be a function all right so let's go and create a function here that doesn't return any value denoted by the void return type and we say print name all right the functionality of this function is only just to print class all right that's all it all it does and in dart you're also now that we're talking about this i'll just mention also in dart it's usually better not to prefix your instance variables or instance functions inside the class itself using this keyword this keyword in dart that this this or that this keyword basically refers to the current instance of this class all right so you could either tell print name to print this dot name or it's actually better to remove this and refer to it as name that's the recommended way of doing it okay so avoid the keyword this as much as you can unless you have to and we'll come to those points hopefully later in this in this course why you may have to do that while you may have to use this all right now we have the print name instance method all right so let's just use it instead of this print function that we're doing here let's just say foo dot prints name all right command s or control s on linux and windows and command sun on the macintosh and then you get the flutter foo bar printed here or you could just say print i'm going to i will now print the name of this person in single quotes we don't need double quotes okay command s and you will see that message being printed here followed by the actual name of that instance so if someone says method or instance method you will then know what we're talking about is a function created at the class level that does some stuff all right so that's short and sweet um okay now that we've talked about that let's talk a little bit about inheritance and subclassing i'm gonna bring a caption here so you know what we're talking about now inheritance and subclassing are so so important in dart and in any other object-oriented programming language that i don't think anybody should like jump over it or um like for instance i know developers working in various programming languages that are object oriented but they kind of steer clear of the object oriented aspects of that language and maybe they don't need it and maybe they just feel like it's unnecessary or they feel like oh it's just too complicated but in dart if you want to become a good flutter developer or a good dart developer you need to know about um classes and um inheritance so so let's talk about inheritance what inheritance in dart is is that it allows you to define a class and then to add more functionality to that class into a new class so let's for instance say we go into our test function here and remove that okay that code and also remove the person class now let's create a class livingthing all right and then we say funk sorry void breathe and then we say print living thing is breathing okay so we created a class living thing and we're saying that anything that lives needs to breathe now this may be an assumption but anyways anything that lives and is above the and it's above the ground and it's basically alive is breathing okay so that's our function on the living thing now you may say okay any living thing may also have the ability to move okay then we have a function called move i'm going to say print i am moving all right so now you may say okay now i kind of want a class called uh cats all right cat is also a living thing one way to do that to go about creating a class uh the cat class is to say class cat and then you say um i kind of need these functions and you'll go and copy it and then you paste them here all right and then you say okay i'm good to go now but one of the absolute paramount paramount qualities of a developer is the developers do not like to repeat themselves and it is such an important concept in programming that you need to avoid repeating yourself that you need to just coin that down now get it straight so that you don't make this mistake as we're doing in this code right now so the first thing you want to do as a developer say how can i grab this code and and it's obvious that the cat is also a living thing so that's where you want to use the extends um keyword that allows you to inherit the functionality inside the living thing class into your cat class so in this case i'm saying cat class extends or read it in english as inherits living thing all right so you can see that the cat class in itself is empty right now but if you go to the test function and i say final fluffers is a cat and then i can say fluffers uh you can see that now that the cat class has breathe and move uh functionalities or functions actually so although cat itself didn't define these functions but they're available for the instance in this case called fluffers of type cat to use so you could just say move and then you can say fluffers okay so if i run this code if i delete everything in the debug console and run this code you can see that the cat instance called fluffer is the same move or i am moving and it will also say living thing is breathing okay now you could also i mean we could also talk about now that we're talking about inheritance and subclassing um actually maybe i shouldn't call a subclassing but i also think it's important for you to understand what subclassing is subclassing is literally the same thing as inheritance subclassing is saying that you have a class and you're creating a sub component like a sub thing of it which may actually have it's a little bit of a strange naming sub because sub means kind of like a subset of things available in that class but it actually is like a superset because it will grab everything like the cat at the moment has every functionality in living thing right but it may not necessarily do that it's kind of complicated to explain but if you hear subclassing or inheritance know that that is what we mean you use the extends keyword usually okay all right now we've talked about inheritance and subclassing so i'm gonna move a little bit uh my notes around sorry about that that i'm looking away from the screen and uh now we're gonna talk about abstract classes all right there's good documentation about abstract classes and what we're going to do here is to just change this class living thing at the moment to abstract and you see that everything works as expected well an abstract class is very similar to a normal class and there's good documentation about what an abstract class actually is from a dart perspective and you can see it says use the abs abstract modifier to define an abstract class class that cannot be instantiated all right so an abstract class is just like a normal class that can't have instances so in this in this case once we made living thing an abstract class if you then go and hear say thing is a living thing right and it says oh abstract classes can't be instantiated so an abstract class is a class that groups logic into itself with the sole purpose of other classes using its functionality okay so if you mark something as an abstract class in dart you what you need to just know in your head is that this is a class that has some utilities that has some code that is supposed to be used in other normal classes all right and no one is supposed to just go and create an instance of living thing in this case instead at the call side you need to instantiate classes of that type so now we can say cat as we did before and we can say thing breathe move or fluffers so that's what an abstract class is it is just a class that cannot be instantiated it's usually like a utility class that other classes are supposed to inherit from all right okay um i can see now in my notes and i'm gonna take that we've talked quickly about abstract classes and i'm going to bring the next topic up which we're going to talk about which are factory constructors so i absolutely personally love factory constructors to be honest with you let's remove our abstract class i'll explain to you what a factory is let's see now we have a glass cat all right um and then in here let's give the cat a name of type string command dot or control dot for linux windows on the name in visual studio code at least to create a constructor you can do that and say create constructor or you could manually create a constructor so you say cat this name okay that's a constructor and also know that um you could make this a const because it is actually using a final field but we're going to talk about that later now we have a cat class here that has a constructor called just cat meaning that in here you can say final fluffball is cat and then you say fluffball all right so now you're creating an instance of the cat class and the name of the variable is called fluffball and the name of the cat is fluffball right so then you can say print off ball dots name all right so that is just normal constructor it has nothing to do with a factory constructor but what a factory constructor actually is is a way for you to construct instances of your classes and using convenience functions so what that means is that if you in your code see that you are creating instances of this class like 20 times 30 times different places in your application using this exact same name fluffball then you need to then create a factory constructor that is a clear sign that your usual use case for create an instance of class is through the same name of fluffball so that's where factory constructors are useful for and as their name indicates is a way to create a product like a factory does uh super fast for you okay so it's the speed at which you can create an instance of a class that the factory constructor shines at all right so let's now look at a factory constructor that gives us an instance of cap whose name is always fluffball all right the way to do that is you would say factory and you would say cat dot fluffball so you say any class called cat which is this class has a function called fluffball which is this factory constructor and then you would put your parentheses in here and then what you need to do is to kind of set up your class instance in this case like if you say curly brackets and say this name is fluff like that that's how you're basically creating an instance of your class but the usual way of doing that is you say this name dude let's see uh factory cat fluff ball and then you would say name is fluff see that i've kind of like forgotten the um uh syntax for factory uh so let's go i'm gonna bring up safari here and let's go and say guard factory constructor i'll bring bring up here factory constructor so let's say factory and let's go and see an example and you can see here it says factory logger like that okay and there's a factory logger blah blah like that so are basically so what what it's basically saying in here is saying that this in this function you need to return something okay so let's close that safari window and what we're going to do in here we're going to say return cat and as the name we're gonna say fluffball all right so that's how you would create like a factory constructor so what you're doing here is saying that i have a constructor called fluffball whose return value is a cat but inside i have some special logic that kind of packages it up just like you do in a factory so let's go in here instead of doing cat fluff ball like that then you can just say cat dot fluffball okay so it kind of like became a um it became like a convenient function in that you can just say cat fluff ball and then you say print fluffball dot name and you can see by default it is or whatever you put here fluffball 2 print and it gets printed to the screen ok so that's how you would create a factory constructor and a factory constructor is really really important when you're talking about class clusters we haven't talked about class clusters and to be honest with you i don't think that we're gonna talk about that in this course i don't think anywhere in this course i've actually talked about class clusters but know that in the context of dart and abstract classes a factory constructor does not necessarily have to return an instance of the same class all right so it can actually return an instance of another class but i highly suggest that you actually go and read about factory constructors as i just did just google factory constructor dart and you will see some examples of it um they are really useful if you're working with a lot of data and you're doing like data parsing json parsing etc but i don't think it's so useful right now for you to know but know that it is there available for you to use but i leave it up to you to go and read more about it yourself okay and we've now talked about factory constructors and um now let's talk a little bit about custom operators so i'm going to bring custom operators here okay now a custom operator in dart is an operator such as an equal sign or equal equal sign for for instance um checking equality um of an instance of an object with another instance of the same object um a custom operator allows you in dart to override the ability of your class to be compared to or added to or subtracted from multiplied with something with your own logic now let's see what i mean by that let's say that you have final uh cat one and that is equal to cat with the name of foo then you say okay i have cat two now with the exact same name and then you'd say if cat one is exactly the same as cat 2 prints they are equal otherwise say print they are not equal ok so these two instances have the exact same name foo and if you run this code now you will see that dart is said it says that they're not equal although internally you may think hmm for me in my project anytime two cats have the same name i want them to be considered equal and this is like where things get interesting because then you can override this particular function or operator at the language level only for your class so the way to do that is you would go and start by writing override with an ad sign and you say bool operator equal equal covariance i'm going to explain all this don't worry about it cat and you say cat and then here you say um other name is me okay and then we get a problem with the hash i'll add that as well so don't worry about all of this um i will explain it in details um all right so okay so let's start by looking at what i just did here with the override notation here overwrite is very important term for you to understand in object-oriented programming and that is wherever you have um a class and you are inheriting from that class in in our case for instance class cat you can see that it doesn't have any extents but by default in dart every class inherits implicitly from the object class so you could just say extends object and that is the exact same thing as omitting writing that those two words so just know that cat comes from object an object internally already defines an operator called equal equal that returns a boolean a boolean is a value that can either include true that can either be true or false and it's great just for saying that is this this or is this that is this this or not kind of like that so a boolean is a data type all right so that operator an operator is a keyword as well in dart basically saying telling dart that we are going to change change as in override the functionality of this equally equal operator that is defined at the object level with our own implementation all right let's actually bring the extents here and go into this object definition just select it right click on it and say go to definition all right and search for operator equal equal you'll see that it is defined right there for you okay and there's lots of documentation about what it actually does so that's this syntax we're overriding we're changing the definition of that function all right so then since this is a simple function an operator in itself is a function it actually you can see it starts it has like a parenthesis here in the parenthesis you get the value that that operator is comparing your class with okay so it's that that value that your class is being compared to also needs to be a cat because you cannot in dart is not recommended that you compare tune classes of different types with each other so here we say covariance covariance is a keyword that you merely use in dart but i think it's important for you to understand what it does is that it tells dart that although at the object level we said that the parameter that comes in is of type object but in our case we are sure that the value that comes in this function is actually a cat all right so covariant tells dart that forget what the super class which is object defines as the parameter type for this parameter because if you remove covarian you see it says cat an object as a parameter but if it's a covariant you're kind of like overriding even that assumption all right so we say okay an equal so we're mean compared our instance of cat is being compared with another cath instance and what we're doing is that we need to return a boolean saying whether they're equal or not and you can see i'm just comparing i'm just comparing the name which is our name with the other instances name all right now when you do that as you saw then we get a problem here which is kind of like a warning that tells you that okay now that you've you've overwritten this um operator you also need to override the hash code all right now to honestly i don't think like hashcode is such an important thing to talk about right now but just know that hashcode is a special number that you assign to your or a special identifier that you assign to your instance of classes that is then used inside collections for instance if you put your instance of of cat inside a dictionary then or sorry or inside a map as it is called in dart which we talked about i believe in chapter four yes in chapter four so if you didn't watch chapter four i strongly suggest that you do that so if you put instances of your of your cat class inside a set or inside a map then the way dart knows that the the keys inside its map or the values inside the set are actually unique it's using this hash value all right so if you see if i go here and say command dot to get a suggestion how to fix this it says create method hash code that is what is required to fix this word so you can see that it's an override which means that this hash code getter was defined on the object class if we go to object and look for that you can see that it is actually defined there and we're overwriting its value and here it says i'm going to go to super and get that value super is our object so as super class that sits up above us all right but if you want to overwrite that in case you in this case you can just say okay don't get the supers hash code just get the name hashtag and to be honest with you this is just a very technical stuff which i don't think belongs right in this chapter six but just know that here we're creating an identifier for our cat class which allows dart to understand that if this cat classes instances are placed inside collections such as a map or a set then it will know if they're unique or not okay all right so now that we've done all of this we can rerun the code and you will now see that it says they are equal that's that's all we wanted that's really all we want but there was a lot of code actually i don't know it's like four lines of code um this is not even considered a line of code it's kind of like a is a hint to the analyzer but uh so you could just say it's pretty much just two lines of code but it is quite a lot of new things to be honest with you for you to grasp so i leave this here so you can have a look at it um and i think for this chapter to be honest with you we've talked a lot now in this chapter about enumeration switch statements classes objects uh constructors factory constructors abstract classes inheritance a lot so it was quite a heavy chapter this chapter six but i suggest that you go and read the also the official documentation for dart because as i said we don't have the possibility to talk about everything um otherwise this course will just be enormously big and that's not what i want to do so please go and read the documentation about the things that we talked about especially especially object oriented programming in dart so and with that said in the next chapter we're going to talk about some advanced features in dart such as future async operations streams and generators so please have a look about at the documentation and i will see you in the next chapter hello everyone and welcome to chapter 7 of this flutter course in this chapter we're going to talk about advanced dart concepts things such as extensions futures streams um async await generators and um generics as well so uh i'm kind of assuming that you've already set up the project that we've talked about in the previous chapter so i'm not going to go through that again and then i'm assuming that we have like some sort of an iphone simulator so or an android emulator or any device that you may be able to test your project on so i'm going to bring up my project here so i'm going to place it right there this is how we left the project in the previous chapter and then i'm going to do command shift p on mac or control shift p in linux and windows in order to select the device and i'm just going to say iphone 13 pro which is a simulator that i have here um right there and then i'm just going to go and say run run without debugging okay so this is going to take its time and i just thought to then use this time to explain a little bit about extensions um as you can see here extensions are the ability for the programmer and dart in order to er are there the ability for the programmer to extend or add functionality to an existing class in chapter six we talked about classes and objects so i kind of um would wish for everyone who is in this chapter to act actually have followed that chapter as well uh i'm actually going to go here and go to do not disturb yeah i am actually there so let's have a look at a simple extension in dart and how we can use that i can see that the programming program is running i'm going to delete the old code that we had and i'm going to bring my face to that bottom right and i'm just going to be a little bit aware of these um captions that i'm displaying on the screen and that they're blocking the screen so i'll just make sure that you can see the contents as as we go on so um let's also remove all of that and then let's just say that we have a simple cat class here who has a name and we can go in here and say final meow is yeah an instance of cat and i can say print and me actually we have to provide a name i can see here and let's just say fluffers and save meow dot's name okay so we print that name and i'm gonna say command s just like that and um perhaps gonna bring up visual studio code so you can actually see the output so command s and you can see that um where are we getting this there are equals oh that's an old command so command is and you can see fluffers is printed to the screen so that's because we have the name here okay so i'm also going to get rid of this caption right now so you can see the entirety of the code so like that bring it down here i'm also going to get rid of my simulator and bring it to another screen okay so now let's say that you want to add a functionality to this or a function to this class that allows a cat to run or allow the cat to jump so one way to do that is to actually go to the cat class class itself and create a function in there but what you can also do is to go and say extension for instance run on cat that's the syntax for creating an extension what you're saying is that you're extending the class call cats with a new functionality that is called run now this is not the name of the function itself it's just the name of your extension and you don't have to really know about the name right now so much it's just when you can go and become more advanced in dart and you for instance create libraries for yourself that you create extensions on different classes for instance in your library and then people or programmers who use your library then they can in basically include specific extensions that you've included in your library in their code or they can exclude them and so just know that it's just a name on the extension so it doesn't mean so much right now okay so then you can just create a function that has no return value called run and then you can say print and cat name is running and you know this syntax from the previous chapters that this is how you format a string and then in here you're basically doing um spring interpolation interpolation i think it's called and you're including that name inside your own string so the result is going to be cat space the name of this cat instance space is running okay so using that then you can every cat instance in your project is gonna get that function called run so you can just say me out run and command this and you can see that it says cap fluffers is running so just know that extensions are they're a great tool for you to use if you believe that there is a functionality that you're adding to an existing class which it doesn't really belong in that class itself but it may for instance belong in the current source file that you're working with so extensions are very very useful and but i also believe that they need to kind of be used with care kind of like sparsely so when you really need an extension you could just go and create an extension and they have limitations and as you get more used to programming in dart you will understand their limitations a little bit better so just know that they're there and can be used another example of an extension is for instance if you had a class person let me say first name property okay so this is an instance property and then you would say uh last name and then you say command dot individual studio code on mac or control dot in linux and windows and you create a constructor for your personal class okay so that's how you create an instance of your person class then you can go in here and you say um final fou is person whose first name is who and whose last name is bar okay and in here let's say you want to be able to calculate a person's full name all right so what you could do is to you could say extension for me one person and then here you could just say i have a i want to calculate the full name so that the result type is going to be a string and then you want to create a getter now we haven't talked about getter so much but just know that it's kind of like a property it's a property that can only be read forever but it cannot be written to so you just say get and then you say phoney as the name of the property and you will say that is equal to dollar first name space dollar last name okay so what you're saying here is that i have a getter whose return type is string and whose name is full name and it returns the first name and last memory with the space in between and then in here you could just say print foo for me all right and command s then i will bring the i'll remove the caption so you can see that foo bar is printed to the screen okay so that's for extensions and i'm gonna note that here in my i'm gonna mark it in my notes that we've talked about extensions all right now the next thing to talk about the next topic is futures and as you can see here future is a data to be returned in the future as its name suggests so um and that is part of something called asynchronous programming if you haven't uh been doing uh programming before you may not be so familiar with the term synchronous or asynchronous um a synchronous task is a task that happens when you ask for it and it returns with the data that you ask for immediately for instance if you say um what is 2 plus 2 and then we'll say okay it's four that's the synchronous task but if you for instance say to your um spouse or your friend go to the grocery store today please and get some milk that is not gonna happen in this instant it's i mean even if you even if you're the grocery stores right next to your house or your apartment then your friend has to go get get ready put put on shoes go to the store get the mail can come back so um that that is an asynchronous task so an asynchronous task is basically a task that whose results are not returned immediately okay so up until this point we've looked at functions that i'm actually going to remove all of this code from here so that we don't have all of that now we only have the void test function in here okay so all the functions that we've written so far have been synchronous functions in that for instance you would say string multiplied by two and then it gets an integer of a and it just says a multiplied by two all right and actually sorry hint so it returns an integer the function call the function name is called multiplied by two it takes an integer as a parameter and just multiplies that integer by two and returns it it's a synchronous operation okay however in dirt if you wanna work with asynchronous operations that you have to use a class called future so let's have a look at that um let's say that you have a function multiplied by two it which it may take some time in order to multiply a value okay this is hypothetical because yeah the multiplication is going to be done immediately but we're just going to assume that yeah this is a complicated multiplication and it will take some time all right so let's say future and then you would say what is the actual future what does it contain what data type can we say integer and then we say heavy future okay and it takes a value of int a heavy future that multiplies by two something like that okay so it says i return a future okay now in here then your your um responsibility is to create and package up an integer and return it inside a future so if you for instance in here say okay return 10 okay you see that it says l10 isn't compatible with the future of integer because 10 is a synchronous value it's right there it's present so what are you doing here then you could say okay what i do return is a future and then you could say oh i'm going to delay this future by a duration of three seconds okay and then you'll see there's a second parameter to this delayed function um you can see it let's see uh if we have a look at delayed function in here you see there is a second parameter called future or a computation so in here what you're what you need to do is just to say okay my second parameter is a function i'm going to ignore its return value well i'm just going to return the value of a okay so let's actually see if we say future delay duration seconds and then we say the parameter is let's say e and then i'm just going to say return a what is this value going to be then you know what we could actually look at the documentation for future delayed so i can also refresh my mind so i'm going to go and open a new safari window and i'm going to say future delayed this is the type of stuff that usually happens anyways if you're programming with dart i'm also going to increase the size so that you can see it a little bit better and let's have a look at a future delay here and here we can see how it's constructed uh how to use future okay so you can see here that there is a function that it doesn't basically take anything any uh value so i think the problem was that i may have just created like a function that um was expecting a parameter so this is how you would do that and i mean it is a little bit strange argument like i'm actually going to clean it up a little bit as well and then make this a constant as you can see it's suggested here and then return so i've written a lot of code i haven't explained really what i've done here but i will do that now so let's see uh we're saying that we're returning an integer in the future so it's not going to be returned immediately it's going to take some time for it to do its calculation okay so and then here let's say a multiplied by 2 as we as we promised in the function signature okay so that's future int this is the name of the function so nothing magical about that and then it takes a parameter that says integer a in the function body itself we're saying okay we're returning a future but we're delaying its return by the duration of three seconds so duration as you can see is a class here if you go in it actually is a constitution okay and then there is a class on top probably somewhere uh let's see constitution in blah blah blah constitution duration operator i believe this is i mean the duration dart it's probably just a class duration somewhere if you look at here class duration so so we're saying that we're creating a duration as a first parameter to the delayed function of the future so we're saying that we're delaying this future's return value by three seconds and then it says okay i'm going to wait three seconds but then i'm after i waited three seconds i'm going to call this function and this is kind of like a shorthand for creating a an inline function you could also do it like this you say okay my function that i'm providing to this function so it's like you're passing a function to the future delay function and then in here you could just say okay i return a multiplied by two and then a semicolon so this is probably a little bit easier to read so um now that we have that um we could actually use this function in our test um in our test function so when you then um i mean now that actually we we've now talked a little bit a bit about future and in order to use a future then you need to know something about async and awaiting dart now async and await are very related to each other but quite different in their meaning and um i just want to now explain actually first async async is a key word in dart that marks a function as asynchronous in that remember synchronous is something that returns immediately and asynchronous is something that does not return immediately takes some time however to mark a function async in here it means that this function internally can execute commands that do not return immediately okay so ac marking a function as async it it it means that this function internally calls other functions that do asynchronous work so let's now say final um result is heavy future and we say 10 okay now that we've done that let me just print the result and you'd be surprised to actually see the result when we do that and you'll see that it is not what you think it's not going to be 20 okay so i'm gonna get rid of this caption so that you can see the the result and i'm gonna clear the results in the console and command s and you'll see that what got printed to the screen is actually the future is not is not what you think it's not the value 20 which should be a multiplied by 2 which should be 20. so what happened here is that when you call a function that returns a future you're actually getting the future back you're not getting its data back so how do you get that data back well by prefixing the function with the keyword await so as its name indicates this keyword is just going to wait for the result of this function to be calculated and then it's gonna go to the next line okay so these two are very related to each other and you'll see that if i remove async then i will get an error saying that well you said this function called test is a synchronous function it just returns void basically means it doesn't return anything and it asynchronously does its work and doesn't have to wait for anything so but then inside the function you're saying wait which means yeah i have to wait some time for something and that's not okay so what you need to do then is you mark your functions with async if internally in that function you're using a weight all right and the weight itself then is used for waiting for the result of the future okay so if you remove this async and then you remove this await everything will just work but it's just synchronously getting the future of the heavy future that multiplies by two and printing it so it's not doing any asynchronous work in here you can see it's just getting that instance so now that we're calling that let's command s and you'll see it's waiting three seconds and then printed the result 20 to the screen okay so that for us was async and in weight and we're going to use async and in a way and await quite a lot in this course so it would be really good if you could have with this information that i gave you if you could just have a little bit of a read about future like documentation on the web so if you just search future dart um and maybe async await and read a little bit about them because they're so important in doing asynchronous work in dart that we just can't jump over them okay all right um so now we've talked about future uh and we've talked about async and awaits so i'm just gonna mark them as done in my notes um the next topic to talk about it would be streams so as you saw here a future in dart is a class that controls the computation of an asynchronous value in order to be returned in some point in the future however quite often in in your client's work or even server work you need to do work that is asynchronous however it is continuous work for instance if you if like i have the time uh displayed on top of my screen on the right hand corner that is a stream of strings it is a it is a stream because it doesn't have an end ready it it's a continuous pipe of information every minute that little ticker up on top right it's gonna increase and it's gonna go to zero six fifty zero six fifty 651 so it is continuously calculating the current time and like sending it down at this pipe now in asynchronous programming and in reactive programming which you may also get into if you're following with this course or if you're following some other course you may actually be interested in learning about learning more about streams and reactive streams a stream is just a pipe of data um that either it either completes or it never completes actually it completes successfully or it never completes or it errors out and dies okay so um a stream of time up there you can see it's not 0 6 50 in the morning and it is a stream of data that never completes because time is just just continuously going forward okay so when we talk about streams we just mean a pipe of data a future that sends data down this pipe that never ends as you saw in the case of a future a future ends it calculates its data and it returns and it says i'm done but a stream in dart is a future that just continues working okay so it calculates some data in the future and it also sends it down the stream and it says oh well i'm not done here's another data here's another data okay so let's have a look at this uh stream and see how we can work with streams okay so let's go and create a stream of um let's say a string and then we say get name okay now in here you your job is to create a string so if you say return hello see that hello is not compatible with the return type that you promised it's going to be a string um so you it this is very similar to how we worked with the future of integer you couldn't return an integer in that future but you have to create a future of integer and inside the function return the actual integer which was the computation if i go back you will see that code here right the future delayed and inside this function you're actually doing the computation all right so how do we create a stream and you could just say stream and then you could say okay periodic for instance or a value okay if you say we return a stream of value and then you could say foo is accepted what this means is that you have a pipe of data but the only value that it contains is a foo is the value of food that's it all right so let's now go into this test function and try to consume this uh stream if you just said final value is gets me and you just print this value and then i'm going to clear the logs here and say command s you'll see that just like future it just says instance of controller stream okay so it is not the actual value inside the string so the question is how do you wait for values inside a stream you could just say okay await it says okay you've actually we could read this a weight applied to stream string which is not a future so dart is understanding that okay you're awaiting on a stream but this is this is not just like a future that you're gonna wait for there's nothing to await like it's not a single value is a stream so the syntax to do that is await four okay so this is a syntax for awaiting for values inside a stream then you could say wait for final value in its name okay and then you could just print the value so this is a little bit of a strange syntax but if you read it in like in english it makes perfect sense you're waiting for values in get's name if you just ignore the final in here okay but read it in english from left to right await for values in get name that's it and then at the end i'm going to say print stream finished working here the console command s and you'll see it immediately said foo and then stream finished working i'm gonna clear it command s foo stream finish working okay so this is an interesting concept but it's still not a stream really i mean we're packaging the full string inside the stream but it's only one value we could have done that with a future so let's take advantage of streams actual functionality of sending down data in its pipe continuously so what we could do in here say stream periodic it means periodically produce values and in here you can see the first parameter is a duration so let's say constant duration of seconds every second okay and then there is a second parameter in here that you'll have to provide if i move my mouse over periodic you'll see that the second parameter is this string function int okay so it means that give me a function that accepts an integer and then it returns a string all right and it understands that it needs to return a string because you're saying that your stream is a string if you change this to an int and then went here um to the documentation and the documentation will actually or the method signature will change to say that uh your you should support you're supposed to take an integer in this function that you provide to me and then you need to return an integer okay so that string i just wanted to show you that that string that was shown in the function signature there it's because we promised to return a string in our function okay so let's go in here basically the function signature said that you need to accept an integer so i'm just going to say value and then let's go in here i'm just going to say return foo so we basically conform to that function signature we said we take some value and you see the value is an integer and then we're returning a string okay so now we can consume that so if i clear this log and i say command s you see that every second the value of foo is going to get printed to the screen and that's actually i need to remove this caption i can see you can't see it you see that 10 times 11 times 12 13 14. so all right um i'm sorry about that the caption was blocking the screen i wasn't aware of that um or actually i was aware of that but i forgot that that was the case in in this as i was talking so you can see that every second the stream is sending a value all right now that's that's basically the gist of using streams you will i'm wondering actually if we're gonna use the streams in this course i believe at some point we are i need to probably look at the um look at my notes yes i can see that we're actually using streams in this course so don't worry about if you don't fully understand streams at the moment because we're gonna talk about streams and um because we're gonna actually talk about streams and stream controllers later in this in this course so just know for now that a stream is like a future but it continuously or periodically can return values and then you can wait for those values using the await for syntax and dart okay okay um now the next topic to talk about in this chapter is generators so generators are very very interesting in dart some other languages also support generators and but not not all modern languages do that so a generator in dart is a function that returns i don't want to say iterable but it returns a list of things but it internally calculates that data in a very simple way that's the best explanation i can come up with to be honest with you let's have a look here i think the best way to do that is actually write a function that does uh creates a generator okay um i'm gonna clear this um and then we have a test function here let's mark lacing okay um let's now go create a generator and let's say we want to create a function that returns the values one two three um so a way to do that is would be to say i want a list of integers okay and my function or get one two three like this and you could say return one two three like that okay so that's completely valid another way of doing that is to use something called iterable and iterables i mean you need to understand what iterables actually are and they're kind of like lazy collections and when you get used to doing more software engineering you will understand more what why we use lazy collections but for now just know that an iterable is a prepared and packaged up list of things but it is not it is not completely calculated when it first begins it's kind of like it's kind of like how a restaurant works in a typical night a restaurant might have for instance 50 customers and when that shift begins during the night not all food is ready i mean it can't possibly be like when cut the first customer comes in we can say that the food for the 50th customer is already ready in the kitchen that's how a restaurant works it it listens to orders of its customers and then it generates the food based on the orders that's how an iterable works okay however a list in dart is an already packaged list it means that it's as if like you go to a supermarket and then you buy ready ready to go food that's already packaged 30 packs of that that is a list that is 30 ready readily packaged food items and then you take away that's how list works but an iterable is more like it's it's a list of like things that gets calculated on the go on the fly all right so um just know that for now so we just said either well and as you can see dart understood that okay a list is also an eye trouble so i don't have to worry about that so it didn't give you an error so let's go and actually instead of doing one two three let's go and mark our um function as uh a generator and you do that with either sync or async okay so and this would be a stream like now the difference between sync with a an asterisk an async with an asterisk is a sync function is an it is a generator function that returns a list of things but it calculates that list of things asynchronously and as you can guess the async equivalent of the sync asterisk it does the exact same thing but it returns a stream and which means it's asynchronously calculating its result okay so when you mark a function as sync you don't then go and return like this because you can see that you can see that it says you're creating a generator function so you have to kind of calculate your results now you can't just return a bunch of things to me okay so to do that you would use a keyword in dart called yield now yield is a very interesting keyword that you would use only in generator functions as far as i know and in here you're telling dart that okay the first value that i'm outputting in my iterable is the value of one so if in here we went and said um i know or say we say four value in gets one two three and then you could just say print value you can see it only prints the value of 1. i'm actually going to get rid of this caption you can see the output it only prints the value of 1 just because we yielded the value of 1. okay so you could just send then say yield one yield two and yield three then you'd see the values one two three so in this function internally then you could do a lot of other important things maybe some synchronous uh some other synchronous calculations and every time you have a value to output then you would basically um you would do a yield and you could also print the entire return value yes you don't have to do a four loop so you could just say print it and then it would say one two three okay but if you do a for loop then you're actually taking advantage of that lazy um capabilities of an eye turbo so you could break out the loop at loop at any time you could just say print value if value is two then you could break okay so let's clear the logs and command s you'll see only the value of one and two gets printed and then as soon as you're at the value of two then you're breaking and that means that this yield was basically never calculated so that's that's like the beauty of generator functions so you could also create asynchronous generator functions as i mentioned and that means that you're kind of like creating a stream of iterables to be honest with you asynchronous generators i've i've maybe used them once or twice uh in in the many years i've used dart so i don't think you're going to use them a lot but just know that they're there and you could use them by prefixing your eye treble with a stream saying that basically you're returning a stream of eye troubles and then suffixing your function with async just like that all right so and then here it says okay you said that you're returning a stream of ideal integers but you're turning only one value in here then you would just say okay one two okay um but then you would say yeah then you have the ability to do whatever you want here like return an actual eye variable okay so i'm not going to talk about asynchronous generators to be honest with you in this course because they're kind of like outside the scope so just know that they exist and you can use them okay i'm going to mark in my notes that we've talked about generators so the next topic to talk about are generics and i'm going to bring up a caption here so generics in programming languages that do support it are there so that you avoid writing the same code over and over again okay so let's say that you i mean this is a very typical example i know it's a little bit cliche but i think it's cliche for a reason and that's because it's such a good example um let's say you have a class that stores a pair of data let's just say class pair okay and then in here you could say okay what pair of data do i want to store okay i want to store value one as a string and i want to also store value two as a string and then you create the constructor for it okay all right that's that's great it's a pair of strings but how do you then pair an integer like two integers then you would say okay i have to have another pair class and this one is an integer but then you have this problem because pair is already defined as a class up there on line seven so you cannot reuse that you cannot have the same name then you would say okay pair of integers and then here you would say pair of strings and you make sure that the constructor name is also correct now i mean you may have also i mean in this point at this point we don't have logic at all in these two classes you may have actually quite a lot of logic in your classes but as i mentioned i think during one of these chapters i think it was chapter one or two program one of the main characteristics of software engineers is that we all dislike um writing the same piece of code over and over again so we try to as much as possible avoid um repeating ourselves so that's where generics can come in so what you could do is instead of doing this pair of pair of let me bring this here let's go and create a class that is generic and you would say pair and then a format for creating a generic class is to write after the name of the class oh just to a less than and greater than sign okay and then open your square brackets now in here then you define your generic names like the data types with usually with single characters let's say that what you want is a pair of any data type let's call the first data type a and the second data type b because there's two values so let's call this one a and this one b okay you would just write them as we just say we say a and b okay so then in here you would say final a value one so you're telling the compiler that okay whatever pair i'm creating the first data type that i accept is a and that should be placed here and then we say okay then the b is the second one and then we create a constructor for this okay so how you would use this then is you would say final and is pair then you would say foo and bar okay and then this is just like a simple it's very similar than to pair of strings that we wrote up there you see it worked as well but now in this case dart is smart enough to understand that names is a pair of string and string meaning that the two values that you pass to this pair generic class were actually then placed for you magically inside the a and b templates that you provided up here okay so if in if in this case then you said okay i have foo and then i have the value of 20 then dart smart enough to understand that oh now it's a pair of string and integer so that's how you would use uh generics basically so i mean there are so much to talk about about generics and how you can uh basically utilize them in order to create very simple classes so that they're so that they're reusing as much capability or as much code as possible without duplicating that code so and talking about generics to be honest with you it could be it's its own entire course we could go on and on four five six hours i could talk about generics so just know that generics are created like this you say class pair and then you would say your generic data types which then in case then in turn get placed inside the definitions inside the class itself so okay um all right now that we've talked about generics um i believe that we could kind of like wrap up this um chapter where we talked a little bit more about advanced topics in dart extensions futures async awaits streams the weight for stream generators and generics okay now i'm actually really happy that we went through chapter number seven which is this chapter because up until this point we've kind of been like preparing ourselves for our launch it's it's now time that we put everything that we've learned into practice and actually start building our project so i'm actually getting goosebumps because it's such an important part of this course that we've actually gone through the basics we've talked about dart we've talked about like some of the basics of setting up the simulator etc etc that it's with great pleasure that i can say okay we've gone through that now and all you need to do right now is just to practice and what better way to practice than to put what you've learned um into application by writing the flutter project that we've been aiming to do from the beginning so without further ado let's then prepare for the next chapter which is chapter eight and in chapter eight we're gonna talk about uh project setup and then we're actually gonna add some dependencies to our project which we're gonna use later okay so let's aim for that and i'll see you in the next chapter hello and welcome to chapter number eight of the slatter course in this chapter we're going to talk about our basic project setup in the previous chapters up until this point to be honest with you we've been just working with dart and kind of like um laying the foundation for learning the programming language that actually um uh it fuels flutter so it's a programming language that you're gonna need to be quite comfortable with in order to be able to write your flutter applications so you're gonna learn more and more about dart as we go on in this course but it is very very good if you can look at the intro chapter and then just kind of like follow along on the chapters up until this point so that you get the general idea of what dart is all about and then how you can use it at a very shallow level i mean i know there's lots of material that i put out on that but we really didn't like go so deep in every topic so i just wanted to give you like a flavor and taste of the different available options in dart so if you haven't watched those chapters please just go ahead and skim skim over them even if you're comfortable already with dart so in this chapter we're going to talk about the project setup and this is the like one of the absolute most important parts of setting up um an application for flutter so if you're if you're thinking of maybe skipping um over this chapter that's also okay if you know what you're doing but if this is the first time that you're setting up a flutter project that then i think it's really good if you can follow along with this chapter so i'm going to go now into um let's do some setup here so what am i going to do i'm going to bring my face to the bottom right here so you can see the entirety of the screen and then i'm going to bring up the caption for the next item that we're going to talk about and in here well we have a um as you can see there is a command that you can issue in the terminal to create a new flosser project so every flosser project has different properties it has for instance a name which is the entire like the name of the entire project um and also one of the main properties of flutter project is identifier now the identifier wouldn't be so important had it not been that flutter can actually deploy to ios and android and an identifier for an ios app and an android app is actually what defines that application as unique as on the app store where ios ios users and ipad os users can download applications and on the um play store where android users can download android apps so these identifiers are as i mentioned in one of the previous chapters are kind of like reverse domain identifiers so it's kind of like if your website is foobar.com and your application is called baz then your reverse domain identifier for your application will become dot foobar.bass so it's kind of like you take your domain name and reverse it so if foobar.com becomes com.fubar and then you put dots after that and then you put your actual application name so these identifiers need to be unique and by that i mean like if a if a developer on the ios app store or google play store is already gone and registered the reverse um basically that item identifier.com.fubar.bass for any of their applications so they said okay here's my application called image gallery but it has a completely random identifier of com.foobar.pass then you as a new developer even if you want to do the same funky uh deployment to the app store you can't register that name anymore because because it is already taken so think of the identifier of your project as what is gonna carry on from the start of where you create your project all the way through to the app stores okay so it is quite important that you actually choose it wisely because if you don't do that wisely from the absolute start unfortunately you will have to do some filling around in the future to go and update that yourself so um so i would i would really suggest and recommend here that you take a little bit of um time to think about what that identifier is going to be what you prefer that identifier to be and what you're comfortable with and what for instance if you have a domain name as a developer for the app store and for google play store so if you have a domain name already registered on your name i suggest strongly then that you use that and if you have domain names personally and domain names selected as like a and for your company then you need to now know whether you're going to release this application under your name personally or if you're going to release it on your company's name so these all play a role but without further ado let's just go and create our project here and um i to be honest with you i personally haven't really thought about whether i want to release this application as a private person or if i want to create it under my company and i think since my developer account is at apple and at google is under my company's name which is pixelity ab in sweden then i'm actually going to use that company's domain name which is pixelity.se because s is like the swedish domain name just as code.uk is the um british one for instance so i think i will do that so let's go to and open a new terminal let's go to terminal um i don't see my screen right now but i'm just going to bring up a new terminal window here and bring it up so that you can also see it um and i'm gonna increase the size of the text so it is clear what i'm typing okay so let me go ahead and create a project so i'm gonna go to my development um folder where i have all my projects and i'm gonna go to projects flutter okay and then as you can see is flutter create and then and then dash dash org as an organization and i'm going to see say se dot pixelity now as i said my domain name is called pixelity.sc but your org needs to be the reverse of that okay so remember reverse identifier so reverse domain identifier so then if your for instance organization is hello dot com then here you would have to write com dot hello alright so i'm gonna say s epixody but you shouldn't do this so if you're following along with this course please just choose an identifier for your domain that it makes sense to you and if you don't have a domain if you if you're not bothered by all of that if you're not going to release your application to the app store you don't even have to care about this just put anything in here you could just say come um making stuff up if that's what you want so it's not a big deal to be honest with you so just go ahead and pick an identifier so i'm going to say s epixody because that's my reverse domain name and then in here you have to write your app application name so um what should we call this application to be honest with you i i mean i personally haven't really made up my mind what this application should be called maybe we should call it uh my personal notes my personal notes or my notes something like that or private notes okay all the private notes or notes list i don't know not my notes that would work sd pixel in my notes yeah why not and let's just call it my notes then all right so let's go ahead and do that flutter create and i can see i mean actually i'm very grateful that we got that little notification on top so let this do its work and um it did its work and it's done and it called something and it created a folder you can see called my notes and on top of this window if you saw then there was a little message printed a new version of flutter is available to update to the latest version just run flatter upgrade so that was not a part of this course i didn't mean it for this to happen but i can't control it either because flutter is a tool that is being developed by google it's an open source tool when there is a new version when you run any of these flutter commands and it's going to check um with the version repository to see is there any new version available and if there is then it's going to give me this flutter upgrade message here so um as i mentioned in the introduction of the course i've planned this course quite a lot but i haven't i can't plan it 100 so things will happen that i hadn't planned for and then we just have to roll with the punches and i'm actually glad that this thing happened right here so you can see how to upgrade flutter as well so as you can see it's very easy just copy just say flutter upgrade okay so i'm going to go at the bottom of the terminal i'm just going to say flutter upgrade right so this is going to actually take some time depending on how big the upgrade is because flutter is divided into different kind of engines as you know flutter can output um binaries or applications for ios it can output it for android it can do it for mac os it can do it for um windows and basically desktop searches and mac windows linux and then you will have web as well so there's quite a lot of things involved in flutter as you can see in here it's like downloading everything necessary in order for you to be able to create android applications so so after that is done you see it goes to the ios tool so it's downloading but it's also i believe after it's done downloading stuff it also needs to make sure that it can build those tool sets so this is a process that might take some time and in order to avoid us having to wait for that entire process as you can see it's now going to web sdk and blah blah so we don't have to necessarily wait for this so i'm just going to create a new oh it actually finished so that was quite fast all right so it it finishes work we don't have to do anything special here um so that's how you upgrade flutter so just run this command as suggested by the flutter tools itself flat upgrade and then you're good to go okay so we've done that step now so we've set up our project i'm just gonna move to my notes here and i'm gonna make sure that that topic is ticked and for the next item what we're gonna do here is we're gonna talk about um we're gonna basically have a quick look around the the environment set up by flutter when you run photo create because the flow to create doesn't just like create an empty director it actually creates the skeleton or the scaffold of your flosser project but pretty much everything necessary for you to be able to run that project okay so in this in this application i mean in this in this step of chapter 8 we're not actually going to run the application on any device that's for chapter 9 and for chapter 10. but what we are going to do is to have a quick look around the project structure so let me go to my notes here and what i'm going to do is i'm going to use this code visual studio code extension which is provided in the path so i can just say code dot which opens up visual studio code in the current folder okay so then once that is done i'm going to bring a visual studio code here i'm just going to take a little bit of care to ensure that you can see the important parts of the screen okay and i'm going to increase the size quite dramatically so it's visible for you as well it is very big on my screen but i think it's like a nice size on the on the actual output video alright so as you can see here is the folder created by flutter create and there are quite a lot of bits and pieces in here and i'm just going to tell you a bit about a few of these folders and what they they represent so one thing that you need to understand about flutter is that it actually is not like um it's not really like react native uh if you're familiar with that flutter on ios for instance it for those who have done ios development uh flutter it outputs a native binary on your on your phone a native um fat binary basically for your uh ios application and it just puts one view on the screen and then it graphically renders all its contents using metal okay so if you're not an ios developer that probably doesn't make so much sense to you but this part that i'm going to mention now should make sense for everybody but when you create a flutter application and the flutter create command basically spits out different parts that may be necessary for your application to run on different platforms one of those platforms one of the key platforms that flutter runs on is ioso that is the folder that contains the native bits and pieces necessary for photos to be able to run in an ios simulator or on an ios device such as an iphone or an ipad okay so this is like as you can see it's the project or the workspace and sorry and the workspace because for those of you who are ios developers you will know that there's a thing called cocoapods and flutter internally actually uses cocoapods for ios if you're not an ios developer just know that every ios or android or web application can bring with itself dependencies and a dependency is a way for your application to bring in code from other people in order to be able to achieve special functionalities so there are various tools available for ios developers android developers web developers to be able to bring in dependencies for web for instance if you're writing a node application you will just use npm which is a node package manager if you're using swift you will probably just bring in for instance spm i think um swift package manager or cocoapods and there's another a third one um which i've kind of forgotten the name of um which i may remember later if you're using android you're probably familiar with gradle and that you can like use for bringing in external dependencies so so if this is a platform of android and this is a platform of ios and here's web and here's um desktop for instance flutter sits on top of these so it can control all the um all the small bits and pieces for these platforms to be able to be packed packaged inside one flutter application which sits on on top here and all these different platforms down here excuse me they can have their own dependency management so the dependency managements kind of sit under one layer under so flutter then talks with these dependency managers and says okay you need to install this dependency for me to be able to work so the reason i mention all of that is that is the reason you can see a workspace here and an xcode project and that's because flutter internally is using a dependency manager system called cocoapods which in turn creates a workspace that links together the main project and all its dependencies if you're not an ios developer if you're not interested in all of this just know that this ios folder is just so that your application run can run on an ios device um so that's that the next part which is important is the test folder which we're actually going to use in this course the test folder is where you create your tests if you're not familiar with software development from before if you don't have a background software engineering testing is the ability for programmers in order to be able to make certain assertions about their code and in order in order to make sure that they can automatically run a series of tests against their own code to make sure that everything is functioning as the programmer intended that to if you are if you if you are coming from software engineering background that know that we're gonna put our integration tests we're gonna put our widget tests and unit tests inside this test folder okay so i hope that covered everybody that's that may be watching this course then you also have a folder called android and this is as you would expect it is putting all the necessary files and folders that is required for your android project to be hosting your flutter application so just know that flutter kind of is a series of tools is like a mobile kind it's like a beautiful sdk that gets injected into these native applications and natively also renders its content so um and just like we had a host ios application here you will also have an android folder which contains all the bits and pieces required for your application to be run natively on android phones and on android tablets so this is as you can if you're an android developer you're probably like already familiar with this like you have your app and build great gradle inside the app folder so there's nothing like fancy going on here it's a simple android application which you can actually uh if you have android studio installed on your computer if you want to you can open that folder and actually have a look around and even run that application as a native and android app on your phone okay so that is our android folder and as you would guess then we have a web folder because i think i mentioned this before but flutter supports uh deployment of flash applications to the web as well so you can actually create web applications with flutter it's nothing that we're going to discuss in this course particularly but if you're interested in writing web applications with flutter you can also google that so have a look at that if you're interested in web applications because though web applications in flutter are relatively new but foster has actually come really far with with that so people are creating all sorts of websites with flutter already sorry about that okay um then we have a little file here called analysis options and um as you can see it says this file configures the analyzer so um if you are not coming from a software engineering background then you may not know what analysis actually means but think of analysis as a way for a flutter to be able to have a look at the code that you write and and correct you where it sees fit so where it sees that oh you've made a mistake in writing something that could be written in a better way then it consults this analysis options yaml file and then it says okay what are the rules that i have to adhere to like do you want me to be very strict about certain rules or do you want me to be like less strict about other rules or do you want me to completely ignore certain mistakes that you're making so the analysis options yaml file as it is pronounced it allows you to basically define the roles that make sense for your project in this course we're not going to talk about so much analysis options to be honest with you but just know that it's there so let me bring up the uh the project structure here again um and the next thing that we need to have a look at which is very very important is this file pop spec dot yaml now um this is a file that i mean one of the things that you you'll need to know about flutter and the basic structure that it creates for you is that there are tons of documentations and documentations are like so so well done in my opinion in in the flutter world where i personally come from like the back-end developer development background like i'm doing django or where i'm doing ios development sometimes documentation can for instance on the ios native world be very kind of lacking so flutter has gone like well above the line of what is required from a developer's perspective in terms of documentation and they provide a lot of documentation and if you're not coming from a software development background the documentation is pretty much like information provided by the developers who created the tool for you in order to help you get better at that tool okay as you can see here there's a file created for you pop special and you can see there's lots of gray lines here prefixed with this hashtag if you remove them you'll see that they become normal sentences but if you put them back they become something called a documentation and a documentation if you're not from software engineering background it means just piece of text provided as an information block to you which is not code anymore so the program is not going to turn this into any sort of sort of a code it's just going to ignore that this is just for you to learn okay so let's go back to this pop specky ammo and talk about what it actually is pop spec yaml is such an important part of flutter that i think that you need to actually ignore i mean don't ignore the comments go and spend some time and read the comments just to understand what they mean so um what i'm going to talk about here is a little bit about what this pop spike yaml actually is it is if you're for instance from coming from a web background and if you've worked with node.js then we will have some sort of a config json file or if you're coming from django you'll have settings.pi file if you're coming from native ios world what would be the equivalent of the config it kind of will be kind of like your info plus file um so i mean it is your it is kind of like a control panel of what your project should actually be looking like its icons the version number its name all your dependencies so these things will be all placed inside inside this file and when you change this file if you're already running your application then flutter are automatically understands changes to this file and then reconfigures itself if it can on the fly with your new configurations if it can't then you may have to restart your application like if you make drastic changes for instance if you bring in a completely new dependency into your project then the project cannot be like re-run immediately it needs to actually recompile and link against that dependency it's just like humanly impossible or computerly impossible for it to do so um so let's have a little look around in this pop specky ammo file as you can see there's a tag here called name and it's and it's a value it's my notes and if you remember from the terminal if i bring back the terminal bring up the text a little bit uh this is what we created right this is the project this is how we created the project so we said flutter creates an organization of seda pixelity and then my notes all right that is what the my notes is for this is your project name my notes all right and this is a little just a little description of what this application is all about now you may be curious about what word is actually went s e se.pixelity or whatever you created your project organization under now you can see i search for it i said command f in visual studio code on in mac or control f in linux and windows and visual studio code and i don't know actually what the shortcut for that fine is in uh android studio i just now heard studios a little bit peculiar about its uh key mappings so it may not be command f on mac or controller for linux and windows so i search here now for sepixology and you can see that there are no results so this particular thing that i stressed so much in the beginning that is very important you choose wisely is not actually something that flutter itself needs as i mentioned it is something that the different platforms that you'll deploy to need so if i now actually say command shift f in visual studio code which searches in the entire project say se.pixolity you will see that it is found in different places inside this project for ios for instance you can see here is in the project pbx approach and for android as well in our build gradle so you'll see the application id became se pixelity my nodes and for ios if you look around here as well you'll see that it is s e pixel in my notes okay so that was just side note um so the other thing that you'll need to know about the pop spec yaml is this version number here and this is the if you're not from a software development background um if you haven't done software development before versioning is a way for you to tell various places that you publish your application on for such as ios app store or google play store what if you have something new in your application so for instance if you and this is this is how software is actually actually labeled like a software has different properties what you're deploying what you're developing here is a fluster application but from the point of a store such as the app store it's it's just a package of stuff with some properties like its name identifier and its version now this version is very important because it is a number usually three digits or i know that google play store actually supports also four digits separated by a dot and these these numbers actually mean something special they if you begin from the left and then you go to the middle and then to the right the left number is something called a major number the middle number is called a minor number and the right one and then most the rightmost number is usually called the build number in normal software development the process is kind of like this that you begin with an idea you say okay my idea is to create a notes application that's that's the first idea that's idea number one then you put one as the major number then you begin by zero and zero okay so that's how a version number is kind of like birth so you say one zero zero that's version one usually called okay then you release that application you say okay i'm fine with that version one and then you're in the kitchen cooking some food and then you say okay um it would be great if i could put like um if i could add the ability for users to be able to delete their notes it's not a huge functionality it's just a little bit um improvement on what i already have in the store then you will go and say okay is that a major idea or a minor idea hmm it's not a major idea a major idea would be like a total rewrite of the application adding massive number of features fixing massive number of bugs etc so it's not a major idea then you go to the minor idea and that minor idea corresponds to this minor version here so you say okay the previous one was zero this one is how big of a difference hmm it's just a small future so let's just say one it was a huge like uh minor idea not major enough to be a major idea but minor but quite a big minor idea then you would probably like from zero to maybe two or three it's not so popular to do that usually would go chronologically in that order like one two three four but you're also welcome to jump versions um in special cases so let's say then you say okay i fixed that and i'll now make it build and send it to apple and google just remember that your previous build was build zero now depending on how your project is structured like you may decide that okay every build that i make i'm going to actually increase this build number so the previous one was zero now it's gonna be one then it's going to be two three four five six blocks so every time you make build and send it out to your consumers even if they're a group of testers or people who are your only consumers may actually just be people who are downloading your application directly from the app store or google play store or from the web they may be interacting with your application as well then you may say okay every time i make a new bill and send it out that's when i actually increase this build number or depending on your project setup you may come with into an agreement with your teammates to say okay we don't increase the bills chronologically but every time we change the major or the minor we actually reset the build back to zero and then we go up chronologically so um i i don't want to go to be honest with you too much into detail about the version but if you're interested in software development and i think if you're watching this course that kind of means that you're interested in software development you'll need to know about this so just know that version is your way of labeling your software and its features and what's new in it with numbers okay so just remember major uh minor build all right but you don't have to play with this so much to be honest with you so i think in this entire course we're actually not gonna play with it so all right uh the next bit of information in the pop special is the environment as you can see there it says sdk now when you see sdk just think of software development kit and this sdk is referring to the flutter sdk so it means that if you share your source code with some other developer who's sitting maybe on the other side of the planet if they get your source code and they want to for instance be able to test this application on a simulator or an emulator on a real device then they are required to have flutter sdk version this or less than this all right so you can actually get your flutter version by i believe if you run flutter dash dash version it will tell you that i'm plotter 281 and that as you can see here it says yeah the sdk required in order to run this application is two one five zero more than or equal to that at least at least two one five zero okay so that's your sdk the flutter sdk the other part that you'll need to know about is this section in the pops wiki ammo and that that is called the dependencies and this is what we're going to talk about actually um right now um and dependencies as i mentioned before uh are ways for you as a software developer to bring in code that other people have written in order to make your application application function better or function in a completely new way for instance um you need to kind of be careful with dependencies just because depending on what dependencies or libraries you bring into your project it can actually make your life better or worse dependencies are um basically when you bring it in a dependency they're usually code written by somebody else or other people that may be working on a library so when you're if you're not coming from software development background then you will need to know this and i'm just going to warn you from from now so that you've heard it at least from somebody dependencies when you're picking dependencies just be a little bit careful in that they may it may be that they initially make your suffer better but since dependencies are code written by other people and other people's priorities change their lives may change so that they don't have time enough enough time to continue working on those dependencies so i have personally run into the issue that uh we brought in a dependency into a project and then after a while we just realized that oh the developer isn't uh actively working on this and maybe even the developer made that library um deprecated and deprecated is the world that a word that you'll get to know when you work more with software development and deprecated kind of means that the library is not supported anymore the library is not is not actively being worked on anymore and the developers are encouraging you to move away from them so when you bring in dependencies what i'd like you to do is just to have a look at who is behind the dependency and prioritize your picking and cherry picking based on a few factors if the divi if the if the dependency is written by a single person um be a little bit careful about that just because single persons priorities may change and they may not be able to like continuously work on a even if if it's an open source project they may not be able to continuously work on that um if independence is written by an organization especially an organization that you have a lot of faith in then prioritize it a little bit higher um at least that's my opinion if a dependency is written by a bunch of independent people under an organization prioritize that also higher than a single person who has a who has a library under their private name okay that doesn't necessarily always mean that a dependency created by an organization is actually better quality it just means that the chances of it being deprecated are a little bit less than uh chances of the same library being deprecated had it been written by a single person under their private name so these may actually to be honest with you sound a little bit high level at the moment and you may think okay why do i have to need all this it's just that it is very easy for newcomers to flutter to get dependent on dependencies in that it's so easy to bring in a dependency and just work with it that people forget that oh this is actually code written by a single person sitting in there in their room just like me sitting here and telling you not to listen to people who are sitting in their rooms but i believe it is very important to try to steer your thoughts towards a little bit more constructive dependencies that are good for your project in the long run but if you're writing an application i just want to release it and don't care about it anymore after you've released it maybe maybe it's okay to bring in a dependency from just a that that dependency that you don't even care about but i would even challenge that idea of releasing an application which you may not care about after the first release but because that's usually not a good idea okay a lot of talk about dependencies but i think that had to be said so we're talking about dependency i'm just gonna bring in the captions so um now here you can also see there is a dependency dependency here by default brought into you by flutter itself called cupertino icons and cupertino icons is a dependency that i believe that the flutter team itself is actually behind so you may be thinking okay what are these dependencies like where do they come from they actually come from normal people and companies so i'm going to bring up a um website here for you and it is called pop.dev i'll bring it up so that you can actually see it here and um you can see that in this website popped up there you can search for dependencies so i'm actually going to copy this cupertino icons from here and i'm going to paste it right there um kupertino icon just enter and i'm gonna press on it and you'll see that it's published by the flutter team themselves okay so pop.dev is the website where you will search for dependencies so you just search for a package and then it will bring up results here for you so um this is how you'll search for dependencies okay um and now that we talked about that let's also talk about something called dev dependencies they have dependencies are dependencies that will bring into your project which are useful only under development so if you're familiar with software engineering the normal dependencies will get linked to your project and then you will they will be shipped with your application whereas dev dependencies there are only dependencies that you under the development time will use in order to make your software better and as you can see here one of the dependencies for instance is flutter test or flutter lens in this case as well excuse me okay so there are lots and lots of things to talk about here and as you can see here in the future actually we'll work with this that you can bring in assets and images and bringing them into your project okay so this is a quick look around at the pub spec yaml and i'm going to let this be here i'm just going to tick in my notes here that pops back yaml we've talked about it now to the important part we actually in our application we're going to need some dependencies in order to be able to continue working with the application now we haven't talked so much about firebase before but just know that firebase is a tool that allows you to kind of go serverless but also have a server now serverless is just a fun funky word that is being used nowadays to describe a server written by somebody else so a server that you don't personally have to write if you don't come from a software development background for instance you're a product owner or a designer a server is where your data sits in the cloud kind of so you as a developer sitting in front of your computer right now you're writing a flutter application and your flash application is going to be installed on ios and android devices and that is the client the client is the consumer of the data sent by the server okay so the server is where the logic sits on a computer in the cloud okay and firebase is a computer in the cloud just think of think of that that is written by google so you control it with simple commands on your computer but it controls your data so your client your flutter application can connect to it and grab the data and read the data and manipulate the data on the client side so now in order to talk to firebase we actually need some um dependencies and firebase um will i'll bring up my safari window here now let's have a look at firebase core i'm going to search for it click on it firebase core as you can see it's written by the publisher is firebase.google.com and just remember that flutter is actually a tool created by google as well so i personally think that anything related to firebase is completely okay to bring in into your flutter application has a dependency all right so um i'm going to go here and then say we need four dependencies for this particular project okay so if you're in visual studio code you can bring um the terminal up uh i actually forgot the command for bringing the terminal i think on my mac is control backtick but i believe you can also always bring up terminal advice going to terminal and new terminal okay now i can see there are two terminal windows here okay now i'm going to get rid of the explorer on the left hand side so you can see that the data a little bit better here there are four dependencies that we need to bring into our project all right and i want you to follow along with this exactly as i'm doing previously what we had to do in order to i mean previously in the previous versions of flutter if you wanted to bring in a dependency then you'd have to go and say you go to your in your pop spec and then add your dependencies manually with special versions and then you have to go to those dependencies top dev websites to see the current version all but with the latest versions of flutter you don't have to do that all you have to do is just to say flutter pop add and i'm going to do that right now so that's how you bring in a dependency all right the first dependency that we need is firebase core so just enter this command it'll take some time perhaps okay then say the same command but say firebase off i'm gonna have a look at my notes basically here to make sure that i'm entering the correct dependencies and i'm not going to talk so much right now about what these dependencies actually are because that is going to take a lot of time as well so let's just bring the dependencies in there are four dependencies so the next dependency that we have to bring in is cloud firestore and let's go to the next one and we say that cloud firestore is the third dependency and then we say firebase analytics so that is the fourth dependency so we've brought in four dependencies at the moment if you look here there is a firebase core which is like the the kernel the main important parts parts of firebase which again is what we're going to use as our server where all the nodes for all our users are going to sit the next one is firebase auth auth is the short form let me see where did it go um here firebase off that is for authentication and um i haven't yet shown how that our application is actually going to look like but auth is for authentication is where our users will be able to register uh log into our application and log out and also get email confirmations to send to their emails in order to be able to verify the account so auth is for authentication and that's what we're gonna use it for in order to make sure that people who are interacting with our application they're actually logged in okay the next part is cloud firestore and this dependency is used for when we actually store a logged in users notes in the firebase backend all right it's just funky names to be honest with you they're just names decided by developers just like me and you so and the next part is firebase analytics and that is for if you use firebase analytics when you basically set up your firebase backend you will get some free analytics in for instance oh which screen did the user go to which button did they press and you can have a look at these analytics when you then look at your firebase console which we're gonna talk about later i mean i know all of these are quiet um maybe a high level if you're not if you're not familiar with firebase you may be like what the hell did we just do and that is okay you don't have to know all of this just know that we are these four dependencies are stuff we need in order to make our application function all right so now that we've added these dependencies you can actually go back to your popspakiano file and kind of have a look here at the dependencies that we added and you can see all of them were added here automatically for you with their latest versions okay so previously in previous versions of flutter we had to do this manually but now you can just say flutter pop ad and it will add the dependencies for you directly to pop special all right so great a lot of things we discussed here it almost took 50 minutes to go through all of these basics but i believe actually basics should take more time to explain than the more advanced stuff because the more advanced you get the less explanation you need so that is why all these basic things basically take time to explain [Music] okay i'm just going to take in my notes that we've talked about all of these topics and i think this is actually a wrap for chapter number eight so chapter number eight we talked about um how to set up our project we've actually set up our project now we've set up our dependencies had a look around uh the default flutter template and we also talked about pop special so that's great stuff in chapter number nine we're gonna talk about my favorite which is the ios app setup and in this chapter actually we're gonna go through a lot of things profiles certificates we're gonna talk about app ids a lot a lot a lot i can see here in the list so i'm really excited actually for chapter number nine so go grab a cup of coffee or a cup of tea and i'll see you in the next chapter hello and welcome to chapter nine of this course in this chapter we're going to talk about the setup of our ios app and as i mentioned it i think it was in um the introduction uh chapter in the absolute first actually it's not a chapter it's just introduction to this whole course um we talked a little bit about what we're planning to do with this application that we're developing here and um two of the things that we're going to do is to actually release the app in the app store and in the play store now if you're not planning to actually do that you could potentially skip over this chapter um but i still believe that if you're planning on becoming a flutter developer you need to know how these things work because being a flustered developer depending on what kind of flutter developer that you actually want to become um with me assuming that you want to become an actual flutter developer where you can for instance work on different applications and release them personally or you can work in like a team con concept uh and in the context of a team where you work with other developers inside a company for instance in order to work on their applications and release them than in the app stores so if you're if you fall into any of those categories that you actually want to release your application then i strongly believe that you should know how to do that yourself so although you may be a part of a part of a team of a huge organization where the release process is its own like process that you basically hand over your source code to them and then they basically build it and repair it and release it but if you want to become like a full-fledged flutter developer or a mobile developer for that matter you'd need to know how to actually release your applications okay so in this chapter we're going to talk about releasing your app or actually we're going to talk about preparing your application for releasing in app store later so what you need to know is how do you set up your flutter application so that you can actually build it later and release it in the ios app store okay and if i bring up the next caption here you'll see that in order for you to be able to build your application and then deploy it in the app store you need an ios developer account and i talked about this previously um that how what a developer account is and that you'd have to apply for it i think it was in chapter one we talked about this but if you've jumped over that chapter you'd need to know that you have to apply for a developer account at apple and once granted that developer account then you're going to be able to get access to a portal portal called the app store connect app store connect is your portal for managing your applications and uploading to the app store downloading some debug information etc which i'm not going to go into so much detail right now and it also has a side note as a developer you will get access something called i think the developer portal or something like that i think it's called i believe so i think we just call it developer portal or developer developer site so you'll get access to that and you'll be able to manage things such as certificates and profiles okay so which we're going to talk about soon actually so let's say that you have your developer account and if you don't have your developer account then please just go and search online for register developer account or just watch the first chapter i have to look at my notes actually here and see if that's what we talked about in chapter one actually yeah i can see here chapter one was titled developer accounts and in that chapter we talked about how to register for an ios developer again in depth so please go and watch chapter one if you haven't done that and if you are planning to actually release your application in the ios app store so sorry about that so now you know that you need the developer account and it costs a little bit of money i think it's about 99 so in sweden it's about 990 swedish crowns something like that or 1000 swedish crowns almost so um now that we've talked about the developer account let's talk about the certificates and profiles because this is the thing that trips up a lot of mobile developers when they come to ios development um i mean i've been doing ios development since late 2000 2007 when there was pretty much no um ios sdk as such it was like just a set of tools and very little library support because originally ios apps by steve jobs definition were supposed to be web applications and then apple just transitioned to disbelief that yeah we actually have to have native applications so they released some tools and xcode was there so you could build some simple applications with ios opengl es what's there so you can build some games as well but how it started was that apple wanted to make sure that the applications that are developed can only be distributed through the app store so they said that okay if i give vandal for instance a developer account he shouldn't be able to create his own app store because they it's just a i'm not going into the details of what why they're doing that there's a whole topic and what we could discuss like a few days we could talk about that whether it's a monopoly or not i don't know so i'm not going to go into the detail about that but what you need to know that is there is an app store the um basically just called app store but you could call ios app store mac apps or whatever you want and apple has control over that so it's apple who sits there and like controls the measures that apps that are published on the app store they're of a good quality for instance okay so apple themselves have a certificate now a certificate is like a piece of paper uh just imagine a piece of paper certificate that they hold onto and they said okay whatever we publish on the app store um it comes from us okay so every app on the ios app store comes actually from apple i don't mean that the apple has written the app i mean that apple has signed the app using their certified that piece of paper okay so and then when the app gets downloaded to your iphone your iphone actually checks is this a is this a trusted application where does it come from so ios as an operating system it can contain and you can install many different types of applications that come from many different types of sources such as the ios app store or you could actually download application that comes directly from a specific developer now all these applications need to be signed they need to be signed with a certificate that is just to identify where they come from so certificate is a piece of paper that you as a developer hold and every application excuse me every application that you develop will be signed using that certificate okay so that certificate is your identity as a developer and it gets kind of carried around in with your application to the destination so if you develop this notes application that we're doing in this course and you sign it with your certificate then your application is going to have that certificate signature inside it so when i send it to apple and then apple is like aha that's this developer who created this app okay and then when apple then says okay your application's fine you can't release it to the app store then apple re-signs your application with their own certificate that is just to make sure that your application after it's been signed with apple certificate can be distributed into the ios app store and downloaded by millions of users around the world so it's just sir just know that certificate is your identity as a developer okay [Music] now now that we talked about certificates let's talk about profiles because that also is a tripping point for some developers um especially if they don't come from like a native ios development background which i do um profiles you see a certificate identifies you in short profiles identify your app so that's like the very short way of saying it so you as a developer might have 10 20 30 applications that you're developing or you have developed each of these applications will have their own identity and that identity at the end is tied to you as a developer so you say here's my certificate here's who i am but when you then create an application then that application also needs to identify itself it will be like here i am i am an application signed with this profile using this certificate so just know that a profile is kind of like an identity for your application and different flavors of that application and a certificate is an identity of you as the person who developed that application all right so and if you notice i just said different flavors of your application and by that i mean that if you're not coming from a development background um if you're for instance coming from a design background and you have a figma file or visio file that you're designing your wi-frames and whatever if you're coming from a product owner ownership background than your probably may have like um working with jira or excel sheets or whatever wherever you put your requirements you may not be familiar with different flavors of an application but if you've worked a little bit close with an app team then you'll know that there are different flavors of every application and those flavors are usually i mean they're usually two flavors one is a development flavor and the other one is a production flavor a development flavor is the application you see if you sit with developers with software engineers that are working on your application on a daily basis they're coding they're fixing things they're fixing bugs adding new features and then they will provide the product to you as a software uh as a product owner for instance or a designer and you will download that flavor on your application and be like okay this this looks fine great now all of a sudden you press a button and that button crashes the application so the application just disappears oh it crashed well at that point if the developers were doing their job correctly then they had had to put some crash analytics into the application that as soon as the application crashes or something bad happens to the application of that flavor of the application that you installed on your iphone or android phone or tablet or whatever and they will get something called a crash report a crash report is as its name indicates it's just a report where the crash information is completely visible and they probably even know which button you tapped at what time and what was the information that your app was carrying at the point that it crashed so it helps them debug and fix that problem now these flavors of the application that you install on your phone on a daily basis were working mobile developers are usually called debug applications and a debug application it's just a way of saying that the developers who created it it created the application have the opportunity then to fix any bugs that may arise with more information than they would usually have had they released this application to the store for millions of others to download so that is a flavor it's a debug flavor or is a development flavor okay and it just means that it's a daily it's kind of like a updating regularly application that only very close circle of people close to the project can download so that's a flavor okay another flavor of an application that gets released by developers could be the production flavor and the product production flavor is the same as the debug flavor but a little bit like some stuff maybe removed from it some sensitive information that may be logged otherwise maybe removed from it it's just like a stripped-down version for security purposes not stripped-down version of like features or anything it's just they make it tighter they make it so that it is a little bit more secure like some extra stuff may be removed from it extra stuff that otherwise developers only may need so when it then gets packaged into this beautiful little uh yeah beautiful little package basically then it will also be a new flavor called the production flavor so now you have two flavors one is like for a close circle people sitting next to the product in the same product room or now that everyone's working remotely maybe people are sitting at home etc and that is like the product team closely developers testers product owners designers uxers everyone that is the closed circle they get the development builds usually and then when you get to sending your application to apple for instance or to google for review then you would get the production flavor okay the reason i'm talking about flavors is that these different flavors on ios at least are basically assigned with their own specific profiles so then you'd have a development profile and you would have a production profile and these prof profiles dictate to your application what it what it can and it can't do for instance one of the capabilities of a development profile in the ios world is that your application can actually be installed on a telephone hooked with a cable or even without a cable and debugged remotely so this is one of the cool things you can do with ios in that you can actually like if i'm a developer sitting here i can get the designer's telephone and say oh yeah you want the application like do you want to actually see what i'm working on yeah she or he would say you would connect your their phone to your computer and enable something called remote debugging and then you would disconnect it and then give the phone back to them and whenever they want the application running live on their phone as you're developing it you can actually run the application with your xcode live under uh iphone or ipad so that is its own flavor and the profile which is the development profile dictates to that application that you can be debugged but if you then want to sign your application with a production profile and send it to apple that profile dictates that this application is not allowed to be debugged and when you create your application and send it to apple you need to make sure of two things among many other things but certificate and profile wise you need to make sure of two things the application is signed with your production certificate and the application is signed also with the production profile which is hooked to the production certificate so first the certificate should be there using the certificate you create the profile with the profile you sign your application and then you send this application to apple apple then looks oh everything is is in order the profile to use was a a production profile and the certificate linked to the profile was also correct a production certificate identifying you as a developer so that was almost 16 minutes of information about profiles and certificates for ios but i think they're so paramount in i mean it's so important to understand that you shouldn't really jump over these concepts as if you're if you want to become a mobile developer it's so important so now enough with concepts now let's talk a little bit about um the developer account and here i actually have a link which i'm going to open in a separate window and then i'm going to bring it to the foreground so you can actually see so here is the developer account as you can see on apple's website and i'm gonna bring my face a little bit to the right bottom right so zoom into the window here and this is actually on developer then you would go into accounts okay so after you've registered an account then you will be able to go in here and sign in with your account and i'm going to sign in with my um companies apple id there we go and then it says okay we sent you a verification code and i have my apple watch here so i'm i'm just gonna say i didn't get a code and text me the code all right so in a short while i should be able to get a verification code here and it is important that you don't show this verification code to other people it's just you shouldn't do that so i'm gonna remove the screen from where you can see it and i'm gonna enter the code that was sent to me it is six digits and it is uh just basically digits and bring the phone i bring the browser up now and i say trust this browser okay [Music] so here you will see that um license agreement has been updated okay so we should be able to review that later so i'm gonna increase the space that this screen is taking at the moment so you can see it in its entirety and you can see that now that you you've logged into this account you should be able to see things such as overview membership people's certificates ids and profiles okay so and then what i talked about earlier which is your app store connect okay so um and what happens here basically is that in the membership people's certificates ids and profiles is where you will manage your certificates and all your profiles as i mentioned before so um here it is very important that you basically set up a good ground for your uh certificates create the dev certificate the the production survey and then you create your profiles after that which we're gonna talk actually about in this um in this chapter so here are the missing pieces for us in order to be able to carry on so we need as i mentioned before certificates profiles and app ids app id is something that i didn't mention before so i think it's just important that i mention what an app id is an app id is additional to the profile that you create an app id is an identifier that apple and you use in order to know which application you are talking with both you yourself and also if you for instance in the in the future are going to enable features such as push notifications now if you're not familiar with what push notifications are they're basically remote notifications remote information that you can send from a cloud somewhere on the internet to a user's phone so when they get their phone they will see oh here is a message from this application you can think of it as remote messages just as if someone sent you an sms or an imessage or for instance if you're using whatsapp or telegram someone writing a message in a chat and then you're getting a notification on your phone that is called a push notification so an app id is used mainly in order to be able in order for you as a developer to be able to specify different capabilities of your application for instance that it can receive push notifications that it can for instance store secure information on the phone etc etc so so when i previously mentioned that you need a certificate and profile in order to sign your application you also need an app id in order to identify your application and its capabilities okay so we're going to talk about that soon actually so now what we need to do here before we actually get started creating a certificate uh is to talk about the keychain now if you're if you're if you have a developer account here and you are planning on releasing your application i kind of can basically assume that you have a macintosh so that you have registered for an account and that you want to be able to sign your application with a certificate and profile however you may be in a group of people who doesn't have a who doesn't have a macintosh and xcode etc but you still want to be able to release your application to the app store so you may want to for instance create your certificate profiles an app id and then later send that information to some sort of a cloud hosting service for for them to sign your application and then send it back to you something like that i have never done that myself but you may be in that group and uh for the sake of being inclusive i think it's important to talk about that um now let's talk about what i've put up here as the caption and that is like the certificates in the keychain you see every certificate gets created by you as a developer sending a request to apple now this request is you basically creating a digital signature on your computer which your computer holds onto then your request you will send it to apple apple says oh you're asking for a certificate okay here's the certificate and then you download that certificate and then when you double click on the certificate it gets installed and hooked to your original request okay so here's the certificate and here's the private key so the private key is just a piece of information that your computer stores digitally on only your computer so that later the downloaded certificate can actually be hooked to it creating a chain okay so your application when it gets signed with your certificate that you then download from apple it actually contains some information about the certificate and the private key and then you send the application that was signed using these two pieces of information to apple so there's a lot of information i know but i think it's important for every mobile developer who wants to release something for ios appstore to know this um now this private key and the certificate they both get stored inside a program on your computer called keychain if you have macintosh and i can bring up keychain actually now let me see which i have three screens here so i don't know which one is gonna get open on so i will bring up keychain here um and i will show you how it looks like so here is an example of keychain and you can see here there's a distribution certificate and a development certificate okay and these certificates i didn't create them i downloaded them but the things under them this is the chain i was talking about this is the key that i created okay so when you request a certificate from apple you actually create this thing on your computer and you upload this thing to apple for them to create a certificate hooked to that kind of not you don't actually upload exactly this but something that is related to this okay so for us in order to be able to continue i think it's important that i actually delete these existing certificates from my computer so i'm just going to go like this and i'm going to be like delete two items all right and delete them just like that okay so now they're gone now what we need to do is um here let me put up the captions so you can see so that was the certificates and now we also need to talk about um we also need to talk about actually deleting the profiles now this is an interesting part if you already have like profiles installed on your computer you may not want to do this but i'm just going to show you this step so that we start with a clean slate okay so you're not supposed to do this if you exactly know what you're doing with your certificates but if if this is the first time you're doing this and there may already be some certificates for you on your computer for some reason then this is the way to actually get rid of them so i'm gonna open up finder um let me open up finder here and i'm gonna bring it up here and what we need to do is to go into a folder called um i believe it's called library and then mobile device and then something called provision profiles okay and you can see here um and i will show you this path again so it's my user library mobile device and then provision profiles okay so after i've gone into that folder i'm going to delete these profiles that are here okay so you don't have to do this if you don't want to and you know exactly what you're doing but i'm just doing it to show you that profiles are always stored in that location for your user okay and what you can also do which i really like is to if you say add columns here and kind of like drag it into your favorites so you don't have to type that path every time so let's just put it here okay so that every time i want to install the profile i can just click here and put my profile there all right all right um now that we've done that the next step as the caption shows here is to delete our existing certificates and profiles from apple's development account so let's go to certificates ids and profiles here on the left hand side and you'll see here i have quite a lot of things stored right here okay you see distribution development development blah blah so what we can do here is to go ahead and delete these certificates on the left hand side you see it's a certificate so there are quite a few of them so what i'm going to do is just to tap on this one and just say revoke revoke tap on the next one and just revoke them one by one so and again if you're new to ios development and you've just gotten your development account you don't even have any certificates so this screen is going to be empty for you so revoke revoke so your screen is gonna look like this all right so now that we don't have certificates i'm also going to go into profiles and delete these profiles so if i just go in here and kind of like say all my profiles and then just delete this is going to be fine as well so sort of problem all right so now i've deleted all my profiles and certificates and that was the goal of this part of the chapter 9 i believe so yeah i've now deleted the existing development and production certs and then that is done with the profiles as well they're also gone so what we need to do now is to create something called a development certificate and just to recap a development certificate is a certificate that will allow you as a developer to run and test your application while you're developing it on real iphone or ipad all right so it's it's not necessary for releasing the application but i personally after many years of experience developing mobile applications i've come to the conclusion that i prefer actually running my application testing my applications are real devices as i develop because you also have emulators and you also have simulators that simulate and emulate the capabilities of iphone and android phones or tablets but i've come to the conclusion that it's actually for me at least better to test my application real phones or tablets so in order to be able to do that and if you have for instance an iphone connected to your computer um and you want to test your flag application on that iphone then the first thing you need to do is to create a development certificate so you need to identify yourself as a developer to apple so let's go to the certificate section and then just say create a certificate and then choose apple development actually sorry ios app development this is interesting it says yeah so it says apple that's very interesting so you can basically use something called apple development but we're not going to do that we're just going to say ios app development at the moment okay so let's do that just choose ios app development and just press continue and here it says create a new certificate and create a new certificate is it's waiting for you to tell it that you're asking for a development certificate and you need to choose a file now this is the magic part you need to now go back to keychain so let me see if i can bring up keychain again and in here just go to keychain access menu and then say a certificate assistant and then say request a certificate from a certificate authority okay so i'm gonna press that and i'm gonna put my company's email here and the common name i'm just gonna leave it as my name all right and then i'm just going to say save to disk all right so um that's what we're doing now then i'm gonna say continue and it says okay i'm gonna write a file on your desktop or wherever you want with that request so save it somewhere that you know where it is actually saved so i'm gonna save that and then say done all right now you see that certificate request in itself didn't create a certificate it's just a certificate request but what it did is that it created a private key and you can actually go to your keys here and you'll see that there was a if i say kind private key so one of these keys is the one that was just created right now okay i don't exactly know which one because it doesn't have a date but it's just one of these so every request for creating a certificate it creates with itself a private key okay so keep that in mind let's go back to my certificates now that that file has been saved on your desktop just say choose file and then go to your desktop and pick that certificate request okay and it's you see here certificate request search sign request and just say continue and then it says okay it expires in a year and you need to keep that in mind because development certificates do always expire in a year and you need to by basically renew them okay so but for now you don't have to worry about that because we're not going to take a year to develop this application so let's just say download and it got downloaded to my downloads folder so i'm gonna bring up my downloads folder uh and actually just gonna show you here like this so here is the file that got downloaded you see it's a cert file all right now this certification in itself it doesn't contain your private key remember the private key is in the keychain so what you need to do is just you need to double click on this all right so double clicking on it you see it will then create a certificate in your keychain under my certificates and login keychain that is linked with your private key you see so this is what you downloaded from apple this is what you created on your computer by requesting a certificate and when you double click on the downloaded certificate these two get hooked together okay so that's it that that is what you have to do to create a development certificate and the key related to it all right now let's go to the production certificate and we need to kind of do the same thing same process in order to create our production certificate so let's go back to all certificates and i'm just going to say plus certificate and i'm gonna say ios distribution app store and ad hoc okay so choose that option please and sorry i'm just gonna not also in my notes here that we talked about the dev certificate so let's go ahead and press continue here and you'll have to do the exact same process as you did for the development certificate and create a new certificate request so let's do the same thing just basically kind of copy and paste the same process go to keychain access certificate assistant request a certificate from a certificate authority and just be careful a little bit with this because i've understood from what i've what i've seen is that depending on what you've chosen here this menu actually changes so it could be that you kind of need to make sure in your keychain that you're not selecting anything so just make sure that nothing is selected and then go to um sorry then go to certificate assistant and request a certificate for certificate authority put your company's or your developer accounts email there i'm just gonna pick solid a b and then save to disk and then say continue and then save it to desktop and since there is a file already there with the same name from the previous step it's going to say are you sure you want to replace it yes replace it and it got saved then i'm going to go here and then choose the same exact file but it's actually is a new file which got rewritten and then say continue and you'll see now there is a download so i'm going to download that and if i go to my downloads folder um here i'll bring it up so you can see as well um let's see i'm going to bring it here you will see that there is a new file called ios distribution that is your production certificate okay so double click on that keychain it's open again and you'll see now you have two certificates here iphone distribution and then iphone developer so these are your certificates and keep hold of them kind of like try to save them and if even if you don't save them it's okay because they're now placed here so you can always export them okay but it's also good practice just to keep hold of them great now sorry about that now we've created a developer and a dis and a production or distribution certificate let's talk about the next step and that is required for us to be able to release or test our application on on phones so let's go back here and to identifiers and in here is where you create your application identifiers and you can see that they're actually tied to a specific organization and identifier which we talked about in which chapter was it that we talked about i think it was actually in chapter eight yes if you have if you don't know what an identifier is please go back to chapter number eight where i discussed that so let's press the plus button here and say that you want to create a new app id okay press continue and then you will choose app here not an app clip and then you will be presented with this screen here so i'm gonna explain to you what all this is so in here the description um we're just gonna print some information here that describes our application and to be honest with you i don't remember what we actually called our application when we created in the previous i can see it was called my notes so i'm just going to say my notes flutter application sample or flutter app all right here the bundle identifier is very important that you actually specify it correctly as we created it in our in chapter 8. so i'm going to bring up the my notes application here i'm going to increase the font size so you can see um if you remember where we created the application with this command you see we said se.pixelity and then my notes meaning that the application identifier from this point on is going to be se.pixelity.mynotes okay with a dot in between all right so if i search for that in our project let's say sepixolity.mynotes you will see there are some results here you see so depending on how you created your floater application depending on what organization you specified this identifier may be different for you but since my identifier in this case is s epixody my notes i'm just gonna copy that and i'm going to bring it here make sure explicit is selected and just paste that bundle id in there okay so yeah it's chosen now if you remember what i said before an app identifier is not just the identifier the bundle id itself but it's also like a list of capabilities that your application can have now if you for instance want to have push notifications you will also need to enable that in here now push notification is not not something that we're going to do in this course so you don't have to do that but all you need to do here after you've entered your app id prefix sorry your app bundle an identifier and a description just press continue and you can see that says okay are you sure everything's fine yeah explicit yeah great and then i say register now that identifier got created all right so um you don't really have to do anything with that identifier right now it's just that you have now registered that identifier so no one else can basically take that app from you so i'm gonna actually tick these items in my notes so that we know we've talked about it all right now the next step is to prepare your uh your application so that it can actually be installed and debugged or tested on real phone now you can't see my entire setup but here i have an iphone 12 pro which is just right here it's a little bit dirty screen but that doesn't matter it's just my test telephone and this phone is connected as you can see with a cable to my computer and it is available for my computer to see so i'm just going to unlock this phone right now with my passcode and if i then bring up my finder so here you can see that it is available here right here okay so it's my telephone and it has a special identifier and if you want to get your device identifier which is what we need to do here as you can see in order to debug on a real device we need a uid to register for our profile so when you i mean this is a kind of like a big thing to talk about because it takes a lot of time but what i'm going to say here is that when you created that development pro and development certificate the next step is for you to basically register your device with apple so that apple knows on which devices you actually want to test your application all right and those devices they're stored in here in under the devices um tab and there are ways to get your device identifier such as going to finder as i just showed here and just tapping on your device now i'm kind of going to do it off screen so you don't see the entirety of what is here so let me see if there's any way for you to actually get your device identifier yes and it is i can actually see here there's a way to get that um so what i'm going to do is i'm going to actually bring finder up here so you see what happens i just tap on my phone now you need to register your device on identifier under this devices tab before you create your profile okay i'm not going to do that because my phone is already registered but you need to do this on your own and the way to do that is to connect your phone or your tablet which you want to test your flutter application on to your computer then go into finder and tap on your phone and then just click on this section now i'm not going to do that here and the reason behind that is that every device says identifier really identifies that device so you could go and register my device under your account so and it's just not a good idea to show your device identifier to others so i'm not i'm not going to be able to do that unfortunately in this course but the steps you have to take is to click here on this label and it will show you a section called uuid copy that uuid and go into devices section of the certificate identifiers and profile section of apple developer account and add that uuid with a name to your account okay so i'm just gonna assume you've done that and if you need some time to go ahead and do that please pause this video and do that so the key is just to get the identifier from here okay there's a way also get your identifier your device identifier from xcode um and that works exactly the same you just have to open xcode then go to um i believe go into menu and then pick devices and from there you pick your device and you'll see it's identifier right there so that was a lot of talk let's say that you've already done that so what we need to do now is to go and create a development profile all right so i'm just going to tick these items in my notes as well so this is the exciting part now we're going to go to the profile section and create a new development profile so click on generate a profile and i'm going to say ios app development and then say continue then it says okay choose an app id you see now your profile is going to be linked with your app so do this drop down here and you can see i'm just going to say my notes and this is the app that i created and for you this id maybe a little bit different the description maybe a little different but just choose the um app id that you created in the previous steps so i'm going to choose that i'm just going to say continue now it's going to say okay which certificate is this profile connected to do you remember i said that a profile is linked to a certificate this is what that actually means so granted that you've created your development certificate in as i talked about in this chapter just select your certificate so and then say continue now here it asks is that which devices do you want this um profile which which device do you want your application which is signed with this profile certainly to be able to run on now these all these devices come from the devices section i've registered many devices so um even some of my co-workers devices which allow us to basically debug an application on their devices as well so granted that you've done that if you go back here then you will see those um see those devices in this list right so i'm just going to say select all just make sure my application can be run on all those devices that i've registered okay then say continue and then you will give it a name so i'm going to give it a name of my notes dival dev profile or just my notes dev okay i'm just going to say generate and you will get some information about when it expires etc also expires in a year so and then you'll have to say download and we're going to do the exact same thing now for a distribution profile a distribution profile is the kind of like the same dev profile but you cannot debug your application with it all you can pretty much do with it is to sign your application with that profile and send it to apple so that you can deploy your application in the app store okay so press plus profile and in this and this time go to distribution and say app store you see distribution subsection and app store so press the continue button then go here and then choose your application so that was the development profile sorry now we have to go to production so i'm going to bring the window a little bit up so that you can see it in its entirety so then i'm gonna choose my notes all right and then i'm just gonna press the continue button here um i'm gonna take it in my notes so we've talked about the dev profile okay so now that you've done that uh choose your assertive again you see it says okay now you're creating a certificate a profile for a distribution then it should be hooked with some sort of distribution certificate and since ios distribution certificate is the only one that we created if you remember i deleted all my other certificates so that's the only one left here just pick that and press continue now give it a name i'm going to say my notes prod production and then i'm just gonna say generate it says okay there you go and you can download it all right now that you've done that you need to bring up your downloads folder where your profiles got downloaded um now you see these are the two profiles i got downloaded except with their extension of mobile provision provision you need to install these somehow on your computer so that you can sign your applications or your ios application with this with these so what you need to do now is to copy these two files i'm going to copy them like this and command c and then bring them into your provision profiles folder i'm just going to cut and paste them there okay so they're not in the downloads folder anymore so there they are there are other ways of installing these profiles some people rather drag it into xcode some people double click on them and those are all fine but there's a little bit of a problem by doing those methods compared with the method i showed you here if you double click these profiles mac os knows how how to install them but mac os just messes up their naming so they will be installed on their very random names so if you come back to your provisioning profiles folder they may be under some sort of a cryptic name that you don't recognize anymore so in this way they basically keep their original name which is very descriptive of what they actually are okay okay that was that so now we've created a um dev profile and a prod profile exciting stuff so what we need to do now is actually work we can say that we're done with this screen here so i'm going to close that and what i'm going to do here then is to what we need to talk about now is to set up our project in xcode so that xcode understands that our application needs to be signed with the correct profiles and certificates so what i need you to do is to go to the ios folder in your flutter project and just right click on it and say reveal in finder okay after you do reveal in finder double click on the workspace in order to open your flutter xcode workspace in xcode and what you'll need to do now is to basically make sure that your signing of your ios application is done correctly so choose this icon on top left in your um i think it's project explorer or something project navigator then on the targets choose your targets and then go to signing and capabilities and just remove automatic signing okay for this course we're not going to use automatic signing i'm just going to take it here in my notes that i've talked about removing automatic signing so the next step is for us to be able to tell xcode that for debug purposes in order for us to be able to run our application on a real phone and debug that application which profile and which certificate it needs to use so what i'm going to do here is to go into this section here as you can see debug on under signing and capabilities and then i can see that actually it is going to it's already using the automatic signing for debug and i'm going to remove that as well okay so what you need what you need to do here is actually pick the right profile here and it says my notes dev and my notes profile sorry prod and you can see it says ineligible and um that is because we don't have a development team yet and alex and i'll explain that soon but for now just go to your provisioning profile and say for debug purposes we're gonna use the mynotes dev um and then go to your release and then say i'm gonna use my notes prod okay and here's a little error here you see it says producing profile my notes pro doesn't include signing certificate apple development blah blah blah okay that's that's fine don't worry about that so what we need to do now is to actually tell it um so i'm going to actually pick here profound search setup release profile insert okay so what you need to do here is to go to your build settings and make sure that your development team here is actually selected you see pixelity is for me and then for you it may be something else so um now what i'm gonna do i mean sometimes uh and i can see signing certificate here is actually not really selected sometimes it can be that xcode kind of goes crazy when we play with certificates and signings so i'm going to close xcode i'm going to do the same thing here go to revealingfinder finder open up in another window here so i'm going to open up the workspace again okay i can see we're still getting the problem provisioning profile minus that doesn't include signing certificate apple development and let's open up our keychain again and have a look a little bit here and i can see unfortunately there is a profile you can see previously we had two profiles and it is very unfortunate because um so in here you can see this this development certificate was created by us you see they're very tightly close to each other these two we created but this is something that xcode has created and that is because xcode tries to do automatic signing as you saw it was saying automatically manage signing so by doing that it created a certificate for me on my behalf which i don't want so the error that we're seeing here is that xcode is now saying that this this profile that you have here is not linked to this thing which xcode created itself no one asked it to do that i didn't ask xcode to do that so when you're working with is a woman just know that xco tries to do a lot of magic for you and if you want to actually do things manually it may get in the way so what i'm going to do here is i'm going to delete this development certificate because i didn't ask for it okay so i'm going to say i believe actually that's the right one yeah so i'm going to say delete delete and now you can see that error went away simply because xcode was like ooh now i understand which one you're talking about and then the provision profile of the prod also is hooked correctly so now what i'm gonna do is as you can see here i've opened the project here and then i have my actual iphone selected here to be able to make sure that your application can actually run on this phone now after all of this hard work is just to press the play button here so i want to do that and i want to let it do its thing and if everything works correctly um it's going to basically then um allow us to run the application all right so now it says now and this is a dialogue that you're probably also going to get what's happening here is that it's trying to sign the application and all its libraries using that profile development profile and since that development profile is linked to a development certificate in the keychain and that keychain is password protected you see the login keychain it says i can't access that certificate give me the password for the login keychain so i'm going to type that and then i'm going to say always allow so let's do it let it do its thing and this may depending on the machine that you're running this uh process on it may take some time i can see it's saying now building so um okay then i got an actual failure here it says cloud firestore wasn't found and this is very interesting um actually i mean i didn't plan for this to happen but it did happen i'm kind of glad that it happened this happens usually when you um when you add new dependencies to your projects such as these big dependencies but they're not really linked to your project yet so the way to fix that is i'm gonna let xcode be here okay i'm gonna close this i'm gonna bring a terminal uh what i'm going to say here is flutter clean i clean ios or clear ios i think clean so this is basically going to clean up how the ios project was set up and all those dependencies all right now i'm going to close actually xcode as well then what i'm going to say is to say flutter pop get and flutter pop get what it does is that it sets up all our dependencies from the beginning and just to make sure i'm going to go into the ios folder and i'm going to say pod install and could not be compatible version okay pod [Music] install dash dash update repo uh hot install uh let's see if we can do an update repo i'm just gonna do that uh without like explaining it right now so much and see if that fixes our problem i'm going to bring up a new safari window and say pod install update repo let's see what the command was but because i've forgotten that what update we have yeah um let's pawn install i believe there is a variant of repo update it's called okay pot install repo update let's see if this fixes our problem and if cisco could not find compatible version for podcloud firestore from blah blah specs satisfying from dependencies were found but they require higher minimum deployment target and that's very interesting so what is happening here is you see the deployment target that we have for our application um what it means is that when we created the project with flutter flutter said that what it does internally is says this flutter application should be run on these ios versions and these android versions and what we're seeing here is that what we're seeing here is that we are using cloud firestore and cloud firestore as a dependency is expecting our application to have a minimum deployment version it means that cloud firestore cannot be used in applications that for instance are trying to run on ios 7 for instance okay so what we need to do here in your um flutter project just say command p in visual studio code and open up a file called um pod file all right you go in there and let's see here we have some stuff set up let's go in here and just say platform ios and what we're going to do is just to say platform ios 13 just just now i mean 13 it's really good because right now is ios 15 is available so you could just say you're supporting 15 14 and 13. so i'm going to do that and then i'm going to run pod install again and this time i can see that things are going a lot better and it's installing all our dependencies without a problem so um what you need to know now what i did here was something that you probably would need to do if you're comfortable with ios development so you need to fix these problems by hand but before i explain what i actually did you need to know about something called pod and i explained this in the previous chapters about when we started in chapter 8 when we talked about dependencies flutter can in can create ios applications ios applications dependencies are basically using uh cocoa pods so cocoapods is a dependency management system for ios applications and you need to just know that you need to in order to be able to do the trick that i just did you need to install cocoapods and there is a good website for that i mean you can i'll bring up my and i say install cocoapods and then i go here and you just say cocoapods and then there is a command that you need to issue in your computer in order to install cocoapods okay so um after you've installed cocoapods then you can go into your ios project and like ask it to reinstall your dependencies so the key here though was for me to uncomment this platform line in the pod file where my dependencies are managed so i'm just going to say now i'm supporting ios 13 at the minimum all right and then i manually ask the io the project to be recreated the ios project to be recreated using pod install repo update so after you've done that your dependencies are generated and then i'm going to right click on ios again and i'm going to say oh i can say open in xcode that's interesting will that work i don't dare to be honest with you do that revealing finder and then i'm going to do that and open a project so i'm going to go now do command do i do command b maybe not let's just run it directly so so i'm gonna then bring up xcode and press run again and let's see if it can then find those dependencies that it couldn't find previously okay so we're gonna let it do its thing and it may take some time as you can see because there's lots of dependencies we dragged in and all i think there were firebase off we had firebase core we had cloud firestore and also firebase analytics so these dependencies themselves can bring with them a lot of other dependencies so um it is important that that then to know that as i mentioned in the previous chapter in chapter eight bringing dependencies is not just all butterflies and balloons in the sky it is actually a serious process you need to consider what's bringing in a dependency means to you and your team and your application so in this case we've only brought dependencies that were officially done by google and google is behind flutter so i think then the you can basically trust anything that has to do with firebase at least so if it's released by the google team that work on firebase of course um so we're gonna let it do its thing i'm gonna just tap here and i can see that it's building quite a lot of files if everything goes according to our plan then the result is going to be that application run on this phone so um it would be very exciting actually to see if this will work as we intend to and as i mentioned depending on the computer that you're using this process may take in the beginning at least quite a lot of time so if you have a powerful computer it may take less time and if you have a little bit less powerful computer it may take some more time and um now that we're waiting i should also probably mention that this process of waiting is only initially something you need to do once the build has been done once it kind of like its artifacts will be cached inside your computer so that you don't have to rebuild the entire project from the beginning okay so um i'm gonna let it do its thing and uh while we're waiting actually we could talk a little bit about quicktime which is a caption i brought here if you're like me and you like to like debug your applications on real phones then you may want to see or show that your your phone's screen and on your computer so for instance if you're sharing your computer as a screen with a co-worker and he or she wants to also see your application running on your phone you will need to use something called a quicktime network quicktime so we're going to talk about that now but before we do that let me just show you that here is now our flutter application run on this telephone so there we go our app is now running now that we've done that all of this is done you don't need xcode anymore so i'm just going to press stop here and what i'm going to do i'm actually going to run our application from visual studio code or flutter application on that iphone all right so command shift b or control shift b depending on which platform you're using and say select device i'm going to choose my iphone 12 pro then i'm going to go to run and say run without debugging you don't have any extensions oh not this file open up your main darp file okay and then say run run without debugging and you'll see it says launching so this is going to actually consult xcode and say that hey xcode here's the flutter application run it on this telephone so and to be honest with you i actually didn't like this that it's using automatic signing it what may have happened is that when we did flutter clea clean you may have messed up our profiles to be honest with you and this is not a good sign it could be that when i did flutter clean it actually messed up the profile so i'm going to open up xcode again and bring up our application again and let's have a look at our profiles and i can see debug no it's fine it's not automatic signing so you don't have to worry about this message that was printed to the screen by uh by flutter so i don't think this something that we need to worry about so now that you've set that up then you could actually run your application directly from visual studio code or android studio depending on which environment you're running your flutter applications or debugging your applications from okay now let's say that that is done um then what you need to do if you want to mirror your application screen on your computer then you can bring up something called quicktime player on your macintosh and then go to file and then say movie recording now this is probably going to hijack my no it didn't hijack anything then i'm going to go to iphone 12 pro and see if it can mirror that phone for me uh is it not able to do that is it because i'm recording my screen or something i'm gonna actually [Music] wait for this debug process to continue let us do its thing first i think i'm probably trying to do too many things at the same time so uh [Applause] i proxy i don't really know what i proxy is so um connecting to the vm service taking longer than except expected and that could be because my macintosh is actually blocking something that flopper needs so i'm going to go to privacy here which is security and privacy and just let iproxy to run allow anyway so that may help flutter then get its process working yeah that could be it because maybe my macintosh just blocked that eye proxy so i'm gonna stop this process and i'm just going to say run run without debugging again let's see if it can do its work this time launching and this time since it's actually built the application previously it shouldn't take long this time before it can run the app so it has already built the app once so it shouldn't really take as long this time so i can now see it says installing and launching so let's see if we can get that to work xcode build done in eight seconds and to be honest with you this is taking longer than i expected it shouldn't take this long to run the application and i can see nothing was blocked this time mac os cannot verify the developer of iproxy and i'm just going to say open i think there is something wrong with the latest versions of mac os and how it tries to for instance verify various tools that flutter is using internally but everything went fine at the end i could actually launch the application from visual studio code and now it's running inside my iphone now i'm gonna stop this so now the app as soon as i say stop the app is going to stop working there what i'm going to do then is to go to quicktime and see if we can get quicktime to actually mirror this iphone i'm going to unplug it the phone and then plug it again and see if it understands that it has to mirror the phone i can see my quicktime is also giving me some trouble and it crashed i mean this is live uh recording of this session so you can see all the problems a developer will have to fix and this is me so let's go to um and see if we can get it to let's see if i can get it to recognize this phone and to be honest with you i mean i'm actually doing this on a separate screen so you don't have to see my face so much but i can see that my macintosh for some reason is not recognizing this telephone so i cannot record it basically on this um uh on this screen right now but if you're doing this at home it's probably gonna work for you so uh connect your phone with a cable to your computer and then go to quicktime player and then with quicktime player say new movie recording and from movie recording just from the drop down choose your choose your um phone and you'll be able to mirror your screen so um now that that is done i mean we actually got to a lot of hurdles that i hadn't planned for we saw the iproxy thing happening here grateful that it happened we saw the error with the pod installation which is the dependency of our project because there was no minimum version set up for our flutter project we fixed that we saw a problem with the profile not being picked up automatically because xcode had created the certificate automatically we fixed that so i mean i could for instance now go and filter these out from the video and kind of like when i actually output the final course for you then everything will just work perfectly so you don't have to see any of that hiccup but i don't want to do that to be honest with you because i think it's so important for you to see what issues you will get as you develop your thoughts or applications it is important i don't want to polish this um i don't want to polish this uh course so much that you think everything is perfect from the absolute beginning and if you're and if you're making mistakes then something is wrong with the way you're developing things but these things happen you need to understand why they happen then you need to learn how to fix them so with that said uh i think then we're good to go uh for ios we've explained everything we needed to explain uh everything worked except for the quicktime thing and i think that is because um i'm actually i have a lot of software open here i am playing stop playing in stuff recording stuff so it may be because of that is a little bit confused and who knows maybe my computer needs to restart so um so with that said let's prepare ourselves for the next chapter and that is to do the exact same thing with it for ios hopefully with less explanation now that we've gone through the basics for android so uh grab a cup of tea cup coffee whatever you want and i'll see you in the next chapter hello and welcome to chapter 10 of this flutter course in this chapter we're going to look at setting up our android phone or any android device that you may have at hand in order for us to be able to run our flutter code on it and now in chapter nine we looked at how we can run the application and basically run our flash application on an ios device and we set up the provisioning profiles we set up the certificates what else the app id at app store can on um apple's developer website i mean there is a lot of work to do and you know that chapter took about an hour to explain everything but when it then comes to the android side things are a lot easier um so i thought in this chapter we're gonna have a look at how we can have an android phone for instance in my case here i have a oneplus pro 7 pro that is connected with a usb cable to my computer so there's nothing special about it it's just an android phone and um i prefer to actually as i mentioned in the previous chapter in chapter 9 that i prefer personally when i'm developing applications to developing floss applications to run my applications on a real phone or a real device as i'm testing now um you may not know this if you're coming from like a design background or a background that's not really related to mobile development in previously but um if you're developing applications for only ios then you have something called an ios simulator um an io simulator is a program that runs on your macintosh that comes with xcode and the ios sdk that allows you to simulate how ios internally works and it allows you to install your applications from xcode directly or from from flutter directly into the simulator and simulate basically how your application will be perceived by your actual users if you're developing applications for android then there is something called an android emulator now an emulator is quite different from a simulator in that an emulator as its name indicates it actually tries to emulate everything about the operating system and the device so for instance an android emulator for an old device for instance that you may get a hold of a device that's five six years old it will actually work slower than an android emulator for a very modern device but had you done the same thing for an ios simulator and simulated an ios device that's five years old it would still perform at today's like at your computer's uh speed because it is simulating ios it's not actually emulating it the way it really works on a phone so when it comes to android you have this possibility to run your application on an emulator which is a lot closer to the actual device that your user will be using so it is not the exact perfect copy in most cases so it's not gonna be like working exactly as a real physical phone but it's a lot closer to the actual physical device that an ios simulator is so given that background i still prefer to run my flutter applications on a real phone and in this chapter if you're interested in that if you're if you have an android phone and you want to for instance deploy your flutter application on an android phone and test it while you're programming it then this chapter is for you now i also have to say that um mean [Music] you don't you don't have to do this but for the entire entirety of this course i'm actually going to be as we're developing the application the notes application i'm personally going to be using my android phone so that um so as we basically do hot reloads and then we write some code and we want to test it i'm not going to show any emulator i'm not going to show any simulator i'm actually going to show my real android phone working now i'm not going to show it with just like i'm not going to install the application here and just show you like this because this is not going to work it's not a good way of showing things to uh to someone watching this course so what we're gonna do is as the first task in this uh chapter we are going to install an application on our um computer called scrcpy okay now scrcp cpy is a is an open source project um that is on github with many thousand stars and it is not like a dependency it's not something that you're going to build into your flutter application but it's actually utility you're going to install on your computer okay so your computer will will then be able to mirror your android phone or your android tablet on your computer's screen so and this scr cpy is absolutely beautiful it's one of my absolute favorite utilities to have when doing mobile development and the reason behind that is that unlike the um solution that i showed in the previous chapter which is quicktime quicktime player where you mirror your ios telephone on your computer but you cannot interact with that mirrored image you still have to bring up your telephone and interact with the telephone and see the interactions either on the phone itself or on your screen unlike that scrcpy allows you to actually interact with your phone or your tablet or your android phone or tablet from your computer screen so you can actually take your mouse and then go to that screen and tap on a button and it will actually tap on that button on your android telephone so it is magical it's beautiful it's open source and free so if you have an android tablet or an android phone and you're following along with this course i highly recommend that we install scrcpy together actually as we're going to do in this course so i'm just going to take in my notes here that i've explained that so um before actually we go about installing scrcpy we need to do um we need to install adb and this adb is like um i believe it actually stands for android debugger or something let's see what actually adb stands for i'm gonna bring up a um a safari window here as you can see adb stands for android debug bridge and adb is a great tool if you want to for instance be able to talk with your android telephone all from the command line so you can send it a message and say hey take a screenshot hey do this or click here or yet close this application whatever so you basically send commands to your android telephone or tablet through your terminal it's um it's fantastic and with with adb i mean having adb install your computer then you can actually install scrcpy which uses adb in order to talk to your telephone and send commands to it and receive images from it etc so with that said we need to install adb so i'm going to close this turn window here and i'm going to bring up terminal i'm going to increase the size of this terminal window so you see what i'm doing okay so in here then i'm going to say brew install cask android platform tools okay so this will then allow you to install if i can using android platform tools then um you will be able to grab adb from that so android platform tools insta installation actually includes adb all right so um i can see that i mean for me you can see that i've already installed android platform tools so i get this message here saying that well you've already installed it but if you have not installed android platform tools before you will running this command will actually install it for you now i don't want to reinstall it so i'm just not going to do this suggested command here but just know that before you install scr cpy you will need to get adb up and running okay and that comes in android platform tools all right so let's let me just go into my notes and say that we've talked about adb so after you've done adb we need to go and i'm going to bring up safari again let's see if i can bring up the window here so you can see what i'm doing as well then i'm going to say scr cpy okay and then you will see that the first suggested website is on github and this is exactly where you need to go so go to scrcpy here and you will see information about how you can actually install scrcpy and it says on linux you can do apt installer crcpy on windows you can do a download here and on mac os then you can do brew install scr cpy so i've already done that so i've already actually installed scrcpy so i don't have to do anything special and um you can see it actually tells you here i'm going to increase the size of this window so you can see a little bit better and it will tell you here that you need adb accessible from your path if you don't have it yet then do that command that i mentioned to you okay so after you've done the installation on your computer then you should be able to bring up a terminal so i'm going to bring up terminal here and as you can see here i have my android telephone and it the screen looks like this right now so it's just on the home screen nothing special then i want to bring up scrcpy but before you do that if this is the first time you're doing this process you will probably need to enable something called usb debugging on your android telephone and depending on how your what your android phone looks like or what it is the usb debugging when you plug your android telephone it will kind of show you um a screen like this so i'm going to enlarge this a little bit so you can see better so this dialog will pop up on your android telephone saying that oh do you want to allow this computer to do debugging on this um on this telephone and what you need to do is just to say always allow from this computer and then press the ok button this is only so that you will be first of all able to install and debug your flutter applications all from visual studio code or from android studio right on your android telephone or tablet and also it will allow you to run scrcpy which in turn uses adb in order in order to communicate with your device okay so that is for usb debugging all right so what we need to do is actually bring up scr cpy so in terminal i'm just going to say ser cpy and as you can see here it's going to talk to my android telephone and it brought up a window which i'm going to slowly bring here to this screen so you can see so i'm going to leave the terminal here because the terminal is actually fueling this thing so if i close my terminal this is also going to be closed so just keep this terminal open or if you're using item for instance like i'm using then you can bring up a new tab and continue working with another command line otherwise you can just close it or you can just minimize this if you're if you're bothered by it so as you can see now i have my android phone here mirrored on my screen i'm actually going to do this so you can see it a little bit better i'm going to bring it right here in between so this is my actual android phone so if i click here with my mouse it actually interacts with my phone so i can bring up my phone here so you kind of see them side by side and if on the if on the scrcpy screen here i press the back button you will see that my android screen changes one more time click on google so it's really interacting with my android telephone here okay so i highly suggest that you actually install sdrcpy to be honest with you it's a great great tool if you're into mobile development or if you want to become a mobile developer so um and regarding what i said earlier about devices i think in you will get really really far with the ios simulator and the android emulator however i personally should suggest that you spend and invest some money into getting devices for for yourself they don't have to be top of the line latest devices but one android telephone and one ios telephone or even tablets will do but preferably telephones you don't even have to have sim cards in them just just the telephone device physically itself so um and i mean if you're getting into mobile development you will kind of after many years kind of have a lot of telephones anyways because you will get like this year's new telephone and then two years later you get another telephone so you kind of pile them up um and you could use those all telephones then as test telephones as we call them all right so that's that part now what we need to do next is to now that our android phone is connected here what we need to do is to go to visual studio code into our project and choose that um so choose our let me see bring up visual studio code here if i can visual studio code this is i have so many screens here so it's a little bit of a challenge to actually line them up all here so what i'll do here is i will get rid of the side window all right and i will bring up then scr cpy on the right hand side and then just resize the screen a little bit here and then like this so i have you this is like my usual setup so i have visual studio code here on the left and then i have my android phone mirrored on the right hand side okay so what then you'll need to do after you've done all of this work is in visual studio code just say command shift p on mac or ctrl shift b on linux and windows and if you're using android studio i don't to honestly know the commands there to select a device in flutter they may be like a drop down or something so please do that so here i'm just going to say command shift b and i'm going to say flutter select device okay and in select device i'm actually going to choose my android telephone which is the one being mirrored here choose an android phone and then i'm going to say run run without debugging okay so let's then see that you can see here it says launching dart on gm 19 blah blah in debug mode so since it's an android application now all of a sudden we just switch from ios to android previously our application was being like our source code was being compiled by xcode and now since we're trying to deploy to an android telephone it's the gradle it's gradle basically that's taking care of the build process so if you're an android developer then you know that basically gradle zero build system and yeah it is working um it is basically doing the build in the background so i'm actually so glad that we got this error right now so i'm gonna take here in my notes that we've talked about in vs code select android and then show android phone mirroring working okay so you see here we got some errors actually when we talked about in chapter what chapter are we on we're on chapter 10. in chapter 9 when we talked about running our application on ios we actually got something similar there was an error saying that oh your uh dependencies firebase they need this version but you're on that version and and the under and the code that actually solved it if you remember we went to our pod file i just put this platform here saying ios 13 because you see we have four dependencies at the moment we have firebase auth we have firebase core analytics and something else which i don't remember let me have a look at the notes here there were core auth cloud firestore and firebase analytics these four dependencies they have their own requirements so they say that we as dependencies cannot be installed on an application that for instance supports a very old android os or a very old ios version so these dependencies are putting requirements on your project so and we fixed that yes uh in the in chapter nine we fixed that um by going into the pod file and commenting out this basically removing the comment from this line and changing it from 9 to 13. so we fix it like that for ios but how do we do it for android now we get a lot of great information here and it says that you kind of need to find this debug default config and min sdk version okay so let's look for default config so i'm going to copy that text and i'm going to then command shift f in visual studio code and search for it and as you can see here we have a little um flutter version name and then flutter version code to integer and i can see here there is information about flutter versions like if you go to our build gradle and there is a flutter version code to integer that is the and the where's the main sdk here min sdk version okay so i'm going to search for min sdk version and here i can see it is 19 here it is 19. and android min sdk version 19 so there's actually quite a lot of places where 19 is mentioned all right and the error itself let's read it requires a higher android sdk version fix this by adding the following to the file build gradle android default config min sdk version okay so if we look at the default config here it's talking about this thing min sdk version i can see that previously this used to be a number and recently it has been changed to flutter min sdk version so i'm going to bring up a safari window and i'm going to say change flutter min sdk version so let's see what people are actually suggesting is there a good command that allows us to do this you see people are still saying that we need to do it like that by changing it to a specific version but i believe there should be a better way of doing this instead of hard-coding it um with the new flutter project with the flutter style you're unable to change the mini sdk version and local properties great okay so if we go to a file called local.properties that's what they're saying here so i'm gonna try to find local properties and i can see here there is an sdk set here but there is no min sdk version so we probably need to just go and fix that up so i'm going to copy paste and i'm just going to say flutter.sdk version 19. okay save that file then i'm going to go back to the main dart and then say run without debugging let's see what happens this time and if it accepts that local properties change that we just made and it's still saying that it won't be able to users running so uh what we could do in here to be honest with you is just troubleshooting so let's just say go back to the root folder of your application and say flutter clean android why is it doing the xcode workspace and then say flutter pop get so if this works properly then it should have cleaned the android code for us and like put the version 19 in our build gradle like this should actually resolve to 19 so let's go to main dart and just give it one more try if this if this solution doesn't work then we unfortunately have to go into our build gradle file and and do what was recommended and put the min sdk version there as a constant value of 19 just to get the code compiling so let's have a look here at um what our gradle build is gonna do so i don't really know what happened with it i it doesn't seem to really be doing anything so one more try run without debugging and see what happens launching i'm gonna have a look at my android phone here as well running gradle task assemble debug and for me it's not running anything at the moment on this on this phone so what we're gonna do is let's go to i mean this solution didn't work so i'm gonna remove that and i'm gonna go to build gradle and put the target sdk version i think that was the min sdk version sorry and here we're just gonna say 19 instead okay like that like it was actually suggested to us so um let's then go to main dart and then say run without debugging one more time and if this solution doesn't work i may actually have to like restart the visual studio code if it's kind of confused for some reason because usually when you say gradle like when you start the build process it actually gives you some feedback it either says that something failed or that yeah i um it then ran successfully and in this case i can see it's not running so i'm just gonna say quit visual studio code okay and then i'm gonna bring up visual studio code so i have a lot of projects usually so i'm gonna [Music] minimize all of these things and i'm going to only open our my notes application so let's go in there to our my notes application and let's give this a try one more time i'm going to go to run without debugging and let's see what happens oh now it's choosing iphone 13 pro in debug mode so that's because i restarted visual studio code and it doesn't know which device to run on so i'm going to say select device and then choose my android phone again run run without debugging and hopefully crossing my fingers here that since we've changed the um version number then it's going to work and i can see here i see so now it's com complaining about multi-decks so i mean this is great stuff i'm so glad that we're seeing all these errors because usually we don't have the possible i mean usually you see in tutorials that yeah everything's working fine uh he clicked there and clicked there and everything worked but here we're actually getting to the point where you see every issue that could arise and then we're gonna fix it together and this is like a day in the life of a software developer things go wrong but then you'll have to fix it so um this multi-dex is something that you'll have to configure and we're going to say use multi-dex flag so i'm going to go to safari and i'm going to paste it here um and then there is a solution hopefully somewhere in our default config you see it says multi-dex enabled so let's go to your to the build gradle in app which is right here you see android app build gradle in your default config as it says here multi-decks enabled just bring it here it's it there and then go to your dependencies at the bottom of this file right here and bring implementation multi-decks right there okay so i'm just going to paste it right there go back to my main guard file here and then say run run without debugging so let's see what happens and there are some warnings here that are printed in red you don't have to worry about them so much right now there are warnings as their name suggests so um you don't have to worry so much to be honest with you as i mentioned so there we go here is um our flutter application now working and running on um on the actual phone so i'm gonna bring then the phone here and you can see it is showing the exact same thing so if i with my mouse go over you can't see that because you're actually seeing my face so um and then you will see the value 3 printed here as well so that's that's great stuff um then i don't know why this uh screen is rotated i rotate it back oh it's because my phone is actually rotated so i'm gonna rotate it back so it's uh it's not rotated in the wrong orientation great so we got a lot of problems to be honest with you there um but that's okay that's usually what happens when we're working with mobile development at least in the beginning when you're doing the setup so i'm actually grateful that we're getting these errors so you see them so you don't just think everything is going to work from the absolute beginning so even though as i said in the introduction i haven't planned all of this that these errors come up i don't want things to be perfect so even though that is happening but i'm still quite grateful that they are happening so what we need to talk about now is something called screen sleeping and um as you're developing your uh application on your android telephone or tablet you'll notice that you will run your application on the phone or the tablet and then after after a short while your screen will go to sleep which means the screen will be locked and then when you try to then rerun or rerun your application or re refresh your application then you will get an error from flutter saying that it cannot deploy the application because the device is locked so that is quite annoying that the telephone does it but it is for a good reason the telephones like for security purposes they have to lock the screen so that if you leave it somewhere on a bench or something in a park and you just forget it and you go away then it is locked so no one's going to get access to your telephones data with that said what we need to do is disable it while you're developing your applications because what you want is a telephone that's always there is available the screen doesn't lock so you can always deploy a newer version of our application to it or as or as long as you you don't lock it yourself manually so what we're going to do is i'm going to bring up the phone here so you see what i'm doing i'm going to go here i'm going to go to the settings screen um here and you will probably need to i mean in order for you to actually even be able to run your application and do funky things with your application on your telephone you need to enable something called developer remote so developer mode on android and on ios is a series of development tools that the phone provides only to developers and in order to get those tools you need to perform a series of actions like a monkey or something on your telephone and um i'm not going to provide instructions exactly how to do that for all different phones because depending on the manufacturer of your telephone especially if it's on android then developer mode is brought into life in a different way so what you need to do is to find out the manufacturer of your telephone and the model of your telephone here is a oneplus pro 7 i believe and then google and say oneplus pro 7 developer options or developer mode then you'll get some information about how to enable that i've already done that so if i go to i believe it's utilities or sorry i think it's system then you can see there then i have an option called developer options okay so in order to disable screen sleeping you have to go to developer option and say stay awake and that is by default disabled all right so um we've now then talked about um developer tools and we've talked about that you can interact with your telephone uh using scrcpy so to be honest with you i think i think that's all you need to know for um for the android setup there is not much more to talk about the rest is just developing our application as usual and then running it on the android phone and then mirroring the screen using a crcpy so that's what i'm going to do for the entirety of this course i'm going to primarily run the application run our application that we're going to develop in this course on this telephone and mirror the screen using scr cpy but you may choose to use an ios simulator or an android emulator or an ios phone or a tablet whatever so i can't provide descriptions about how to do all of those things because that is a complete course of its own but at least now you have the tools and the necessary information in order to understand how you can actually deploy to an iphone and an android phone all right so uh with that said now we can say that we're actually good to go on android um and in the next chapter which is chapter 11 we're going to get to some juicy stuff which is uh setting up our project on firebase and if you remember from the introduction we're going to use firebase for our back end so um then you know what's coming in the next chapter and uh now you have the tools necessary in order to get the app running so with that said then let's go and configure our firebase project in chapter 11. hello everyone and welcome to chapter 11 of this course in this chapter we're going to talk about our back end setup which is with firebase um and i'm as i as i've said it before i kind of assume that you've gone through the chapters of this course chronologically so you started from the absolute beginning introduction and then you're following along so there's lots and lots of lots of information as you can see it's about eight hours of information before this chapter so i feel like since i've explained everything so thoroughly in all those chapters i'm not going to go through all that again so i will jump over stuff that i've already explained so i if you haven't watched those chapters i really suggest that you at least skim over them a little bit so you see so you get the gist of it um now i'm looking at my notes and i can see that in this chapter as the caption shows here we're gonna set up our back end our backend is using firebase and while developing this course i contemplated creating a like as a part of this course have a custom backend as well that we do with django i personally do django development uh for back-end and websites like rest apis and also for simple websites as well but to be honest with you if i then go and create a simple back-end with django and then show you how to integrate with that using flutter it really has nothing to do with flutter like the backend part has nothing to do with flutter itself so having that issue in the beginning of this course i was faced with a challenge of do i go into the rabbit hole of creating custom back for this course and walk you through also creating a custom package which has nothing to do with flutter and flutter is the reason you were watching this course so i was faced with that challenge of whether i should do that or just use uh firebase and i choose and i chose firebase simply because it is a product by google it is kind of like serverless so it is a server without you actually having to write code as such so i picked firebase for its simplicity so that we can get the backend working up and running without so much work and i hope that you understand that that is the reason that we're not doing a custom back-end but firebase is a very reliable uh back-end created by google and it has all google's financial backing for further developments and for support so you don't have to worry if you're picking firebase and if you're thinking oh is it going to continue being supported the quick answer is yes it is going to be supported it is so big everyone's using it and it's too big even to fail i would say right now at least for the uh upcoming uh next few years i would say i can't predict the future for 10 20 years in the future but for now you don't have to worry about that so um so that's what we are going to do in this chapter i'm just going to take it in my notes um now previously when uh flutter came out like in year 2020 or even the beginning of 2021 if you want to integrate with firebase you have to do a lot of custom work now in the recent versions of flutter there is a a command that you can issue from your terminal it is called flutter fire cli and this command is amazing because like the work that you have to previously do manually a lot of custom work dragging files and p lists and jsons configurations app ids etc etc it was such a big undertaking that a lot of developers would make a lot of mistakes during that process and it was just not good so um there is now a command that you can issue from from your terminal which allows you to do all that custom work but it does it for you so you don't have to do do that manually so as i provided here there is a link i'm going to open that link if i can somewhere let's see if i can bring up safari it opens in a wrong screen i'll bring that screen here so you'll see it as well enlarge that screen and also enlarge the font so it is more visible so you can see it says fluffifier overview and it says get to know firebase for flutter we recommend starting with the get to know firebase for flutter code lab and video okay so there's a video here if you want to watch it and uh and it says okay if you're migrating your existing project then look at the migration guide migrating if you're not familiar with that term uh if you're not coming from a software engineer background migrating economy so you have an existing thing and you want to make it newer like and put in new stuff in it so you kind of migrate your information from the old project to the new one so but in this case we don't have to worry about that because we're we've created a brand new project so there's no existing firebase installation in our application that we have to worry about okay there's a lot of information here you can see it says using the cli etc etc and that is actually what we're going to do now we are going to have a look at how we can install the flutter fire cli and you can see here it says you should execute the dart pop global activate flussifier cli and then you issue flutter fire flussifier config so let's start by copying this code from here copy it and i'm going to bring up my terminal and i'm going to increase the size of my terminal so you actually see what is happening here okay so i'm gonna paste that command in and i'm gonna let it do its thing i've already done this installation before so for me it may actually go a little bit smoother or a little bit faster but for you it may take a little bit longer depending on whether you've already installed flat of rsli before or not so now that that is installed the next thing you will have to do is you will actually need to make sure i mean it's not provided in the documentation but it's something that i'm providing for you because i know that i've personally run into this issue before so um this flutter fire cli it will give you this command as you can see here flutter fire okay and if i in my terminal say which flutter fire you can see that flutter fire is installed in this folder so it's under my personal folder on my computer slash dot pop cache slash bin and then right there so unfortunately when you install lots of fire cli it doesn't it doesn't tell your terminal where it is installed so if you then immediately after that say flutter fire and then blah blah blah as it is mentioned here classifier configure your terminal will most probably say that what is flutter fire so it's not provided here in the documentation but i'm telling you here as you can see in the caption that you need to tell your terminal where flutter fire is actually installed okay so um then what you'll need to do is uh to do as i've mentioned here you can see i've said that you need to change your path and include your home folder slash pop cache slash bin so if i go to my terminal configuration if i say um in vshrc you can see at the top here somewhere i should have there you see it says export path and i say okay my new path is the old path plus using this uh double column here or column this folder as i've mentioned here in the captions at the bottom of the screen so you will need to do this as well so i'm going to quit vim now and then after you've done that make sure that you source that configuration so in my case i would have to say source zsh rc and that will read the paths um fresh otherwise you could also take the high road and like close your terminal completely terminated and then start it again which in turn reads the configuration and brings flutter fire a path into existence if you don't want to source that's what i mean so now we've talked about that now let's actually talk about what the firebase cli is it is a um actually let me make sure i tick all of these items that i talked about in right now let me just mark them as done in my notes so um so what you need to do now is what we need to do now is to talk about firebase cli and um as you can see here is a cli to help us interact with firebase right from our terminal now um this this used to be done manually previously in that you would have to go to firebase and like create a whole separate project and then integrate that project into your flosser application so you don't have to do any of that anymore so um what you need to do now is as the next step is to install the firebase cli which does all of that work for you so i've provided here as you can see there is a command here that you can issue and then you can go to a firebase google com docs cli install cli mac blah blah so i'm actually going to go to that location in my web browser here so you can see what i'm doing here and you will see there's a lot of information provided here i'm going to bring up the uh i'm going to make the size a little bit bigger i'm going to bring my face maybe to the bottom right as well so you can see more information on the screen and you can see for mac or linux then there is yeah let's go here mag you can install the firebase cli for macro linux using one of the following options so standalone binary blah blah so you need to have a look at this documentation on on how you can install the firebase cli on your on your computer whether you're using mac or whether you're using linux or windows so so after you've done that after you've installed the firebase cli you will actually need to log in in your into your account using that firebase cli so let's let's do that let me actually in here um let's bring up our project uh in visual studio code so i'm gonna bring it up here and bring up the right caption as well so you see what we're talking about we're going to talk about firebase login and log out you see when you want to integrate your flutter application with firebase you need to create a firebase project on something called the firebase console so this project is pretty much the configuration of your firebase backend on firebase's console on their website so you need to configure a backend so what we need to do here is now before we can actually configure it back in in your terminal you need to tell firebase what user you have because i personally have many google accounts and any one of those google accounts can potentially have many flutter sorry many firebase projects because firebase projects are linked to your google accounts okay now in order for our firebase cli to understand where it needs to create the project you need to tell it to log in with an account all right so the way to do that is to bring up terminal and as you can see here is my terminal and i'm going to clean this a little bit i'm going to bring up the font as well so it's quite ginormous and that's okay so what you need to do now is to tell it to log in so i'm going to say firebase login okay it's gonna do its work and it's telling me i'm already logged in with this account if you haven't logged in with an account then you're gonna get a prompt telling you uh okay which email and password do you wanna log in with so now um it may be actually worth it to be honest with you for me to log out right now so that you see the entire process so i'm a bit hesitant to log out because uh i actually have protected my google account with a security key so i don't have the key right here and i hope that i can find it so for the sake of for the sake of actually going through this process together with you so you see how it works i'm gonna log out so let's log out here so i'm saying firebase logout and it says there is a new version of a firebase tool so let's copy this here and i'm gonna see if we can install um what did it say npm install global so let's copy that here global firebase tools okay if it can do its work then before we can continue and npm is something called a node package manager and it is kind of like if you're working with node.js if you're developing for instance node applications which you which you don't have to know about it's just a way it's like a tool kit for creating applications uh remove the existing file and try again or npm with force okay npm install global with dash dash force i think yeah so it's it's like a dependency management for node applications and firebase tools is a node application so that's all you need to know really i mean there's there are courses available about node and node.js then you can actually have a look at how they work etc so i'm not going to go into details about that so before i could i mean i could have actually done a firebase logout without all of this but i just want to show you that things aren't planned like i can't perfectly plan things here and when i tried to log out it said oh there's a new version of node available blah blah so now that i think sorry there's a new version of firebase tools available that you can use that you can install with npm so i did that so let's now say uh firebase logout okay so the logit actually was successful previously and so let's now say firebase login and it says allow firebase to collect cli usage and error reporting information i'm gonna say as a developer to be honest with you you may you may be tended to say no like here but if you are a developer you can put your shoe you can put yourself in the shoes of another developer working at google working for firebase and they are trying to get some information about how you use the cli and whether they can learn from your usage of the cli in order to make the cli better so i usually say yes to these things especially if there's a developer asking for permission so but you can say no to this if you want to so i'm just going to say yes and you can see here then there's a screen provided here asking me to log in with one of my google accounts all right and i'm going to pick my company's google account because that's what i usually use all right so i'm going to choose that and it says firebase cli wants to access your google account and it says okay what permissions it's going to use you can have a look at this information if you want to if it concerns you so if you if you're concerned about any of these things please go and read the links provided here i'm just going to say allow and once that is done you will see that it says firebase cli login successful and then you can pretty much just close this window safely and now it says logged in as pixelityav gmail.com so i can say firebase login again and that would be the prompt that you saw in the beginning of this video that you are logged in alright good that was a lot of information now now that you are logged in with the firebase cli you actually need to configure a firebase project all right and we do that with the flutter fire cli which we installed in the beginning of this chapter using this command dart pop global activate all right so what you need to do now is to issue the flutter fire configure command as i've shown here down at on the left hand side so i'm going to do that flutter fire configure so it will fetch all the projects that i've already created in my google account and it says okay these are the projects available flash chat fluffer note guessing chords random project testing or you can create a new project now i'm going to choose create a new project here okay and it says okay enter a project id for your new firebase project so what i'm going to do here is i'm just going to type my notes all right so as you can see my notes is the name of our flutter project as well so my notes now i'm going to say okay i'm going to create the same project called my notes okay i'm going to press enter here i says yeah i'm going to create it and it's probably i mean you can see that we immediately got an error saying that this project already exists and you can see um command blah blah blah yeah fail to create a project because there's already a project with with id mynotes please try again with a unique project id so this is basically telling us that hey someone else has created my notes and it wasn't one of the projects that we had created because if you if you have a look at your if you open uh your web browser and say firebase console go to your firebase console and uh let me make sure that i'm logged in with my pixelity account yes and if i have a look let's see dismiss let's see get started firebase helps you watch demo yeah we are logged in with that account so i can actually see maybe i don't have any projects set up here which is a little bit weird because we actually saw that there were some projects set up under this account so i don't understand why the firebase console so it's not showing them um firebase console backed by google firebase console google yeah there they are okay so it is on console.firebase.google okay and i can see that my notes application is not an application that i own i haven't created that so what it is saying is that globally firebase projects have an identifier and now i've entered an identifier that is already taken so what i'm going to do then is i'm going to issue the same command uh firebase flutter fire configure and this time i'm going to give it a little bit more information about the project name so that makes it a little bit more unique so i'm going to choose create a new project and then in here in the name of the project i'm going to say mynotes flutter project maybe someone has already taken this as well i don't know so it's doing its thing it's doing its magic basically so let's have a look and i mean this is okay that is taking some time it is doing a lot of work it's setting up like the ios project and android project etc so this thing used to take a lot of time to do by hand like maybe 10 folds the amount of time that this cli is taking so i'm not so bothered by the fact that it's taking some time so and here it will actually tell you okay which platforms do you want to select and as i said like flutter allows you to create web applications android applications ios applications and also uh desktop applications or four platforms and then here it says okay which ones do you want to create for our project right now you can just say android and ios you don't have to worry about like um mac os or linux or windows and web but you have the ability to do that if you want to so choose android and ios for now and press enter so it's gonna do its work so let it do its magic and now this is this is the amazing part that you had to do manually before you had to previously go and register like your application with apple and then go and register bundle identifier and then put the bundle identifier manually in firebase and then download some files put those files in your ios and android project now now you don't have to do that anymore here it just tells you which bundle identifier are you using for your project and if you remember from before when we created our flutter project from the beginning we said flutter create and then an organization which for me was s e dot pixolity do you remember that command it kind of looked like um i mean if i bring up terminal maybe i can even go back to it flutter create do you remember this command i will zoom into it a little bit so you can see better this is how we actually created our project we said flutter create.org as he pixeled in my notes so the bundle identifier for this application will be sepixolity.mynotes however since sc pixelity is the reverse domain for me this won't this won't be the case for you so go back to how you created that identifier for a project using your organization name and you now you have to paste that in here so you will see i'm going to say s e pixelity dot my notes okay so enter that and it's going to configure your ios project for you and that was it so it has now set up everything necessary for your project to work so i mean you may you may just think oh well this was this was so little and what did it actually do but for me who's been working with firebase and flutter for a very long time this is all magical because it did a lot of work it configured your application on the firebase console it actually registered an android and an ios project hooked into this firebase project downloaded the configuration files place them in the exact correct place in your application so it did a lot of work but you don't really have to know about that so um now if you want to kind of see the result of it if you see here the output of this says that there is an identifier associated with your ios app and then there's an identifier associated with your android app so that's what we're going to do now let's now make sure that these identifiers are correct and that the bundle identifier that we provided to the cli is also placed in the configuration file correctly so copy this for instance ios identifier that was created for you so copy it and then search for it in your entire project and then you'll find a little file here and let me bring it down it is called firebaseoptions.dart so this is where ios is configured and let me bring this like that so you don't see it and this is where the android project is configured you can see the um app id is right here and the api key is right there so don't worry about this i mean you should not show your api key and app id to anybody um so but since i'm developing this course for you i have to show it i can't just go and censor it but don't worry about it by the time you're seeing this um video by the time you're seeing this course i've already deleted this project from firebase so there's not going to be any security risk involved so um so that project isn't going to exist even if you know the api key on app id so don't worry about that but if you are developing your own application just kind of be careful who you share your api key and app id with all right that was a lot of information a lot a lot a lot so um and i'm gonna actually tick here that we've talked about that i create a new project and yeah that's that's all working as it should so i'm also gonna go here in the captions and i can see that i have some information here about enabling multi-decks and multi-dex was something that we've already enabled in the previous chapter which was chapter 10 for the android project so now everything should be working as it did before to be honest with you so if you in your visual studio code or android studio if you're developing under your flutter app with android studio you can also go and select your device to run on now in the previous chapter you saw that for the entirety of this chat in this course i'm gonna use an android phone to develop uh our application so you may choose to use an io simulator an android emulator or an android phone or tablet or ios phone or tablet so but i'm gonna use a real android phone and as you saw we have the ability to bring up scr cpy to mirror the android screen so i'm going to bring it right here change the size of visual studio codes window a little bit so you can see the android um telephone right there as well then what i'm going to do just to make sure that the project runs after all of this work that we've done so that we haven't broken anything really let's then go and debug the application sorry run it without debugging and this is this is why you will see this is the result of all the work that we've done pretty much nothing this is like i mean it sounds funny to say it because we did a lot of work with the firebase project but there is nothing that you can see on the screen and that's that's the reality of doing software development you may be putting a lot of work sometimes in doing something and this result isn't immediately visible all right so but what you have done in this chapter was that you actually set up your back end with just a few commands you installed two clis the flutter fire cli and the firebase cli you logged in with firebase cli and then you set up your backend with the flutter fire cli all right now just to make sure everything is set up properly also you can bring up your web browser i'm gonna bring it up here and i'm gonna say console.firebase and let me make sure that we have our notes app here you can see my node slatter project and you can click on it and you can see how it is set up for you you can see there is an android app setup and an ios app setup so you didn't have to really do anything now there's lots of things you can do with firebase which we're going to actually play with throughout this course but not right now just make sure that your firebase project is created for you by logging into console.firebase.google.com many dots all right and we've talked about this now running the application on an android telephone so that was already set up so we don't have to talk about that now now that you've seen that you've set up your backend you're ready to go and uh so i can say congratulations so that's in order now the android setup is already done so i can see that that is set up we don't have to talk about that either however what we do need to talk about is what we're gonna discuss in the next chapter so in the next chapter we are for the first time in this course we are going to talk about the uh footer code actual thoughts or code we're going to start writing a simple registration screen so using this registration screen our right now hypothetical users are going to look at the screen and say okay i don't have an account with this application i'm going to register myself so then you will be able to they will be able to enter their email address a password of their uh choosing press some sort of a button and we will then talk with firebase and say here's a new user register that person okay so that's all for the next chapter which is chapter 12. so grab a cup of coffee cup of tea whatever you want to do get refreshed then and i'll see you in the next chapter hello and welcome to chapter number 12 of this filter course in this chapter and which i'm very excited about we're going to talk about a basic register screen well up until this point we've been really configuring our i mean if we go chronologically we've had the introduction we've gone through so many chapters to talk about dart and its basics and even some more advanced topics such as generics and then as soon as we did that then we basically started learning about setting up our iphone and android application also after that sorry the iphone and android application together with certificates profiles and got scr cpy working so there's been a lot of information up on those till this point so many hours of information that you can go back and watch and i strongly suggest that you actually do that because i've explained everything in such extent extensive detail that i feel like explaining all those things again and again will be a waste of time both for you and me and in this chapter we are going to use all that information that we've learned from the previous chapters and start actually creating a registration screen a simple registration screen in our floater application source code that talks with firebase and firebase we set up in the previous chapter if i'm not mistaken so have a look at that chapter if you haven't set up your firebase app back-end or at least i mean we haven't really set up anything we've just like well yeah actually set up yeah we could say set up um but we haven't really configured in such great details it's just like we've set it up so have a look at that chapter please if you want to um before you continue with this chapter so so i'm gonna go to my captions here and just ensure that i can show you the correct captions now what we need to do in this chapter is to start working on our registration screen and what i'm going to do here is bring up a caption for you so that you know what we're going to do the first thing you need to do is to bring your visual studio code or your editor of choice on the screen so i'm i'm going to do that and then i'm going to bring my android phone mirrored on the screen with scrcpy and then i'll see if i can bring my face to the right so you can see a little bit of a bigger screen and what we need to do here now is to go in this main dart file and remove everything that is a comment now if you're coming from like a design background or a product owner or um like in wherever whatever background that is not software development related if you're coming from those backgrounds then you may not know what a comment is however i'll tell you now a comment is a piece of information piece of text that is written inside a source file such as this main dart file that doesn't translate to an actual code so it's information placed there usually for other developers or whoever is looking at the code so that they understand the code a little bit better okay comments in dart can be created in different ways however the most i mean the most usual way of doing it is with double forward slashes as you can see here and a space and then some text all right so i'm going to need you now to go into your main dart file and we're going to remove all these comments right now because they are basically creating a lot of noise for us right now okay so let's go ahead and remove all those gray lines or whatever color they're displayed on your screen they may be green depending on your theme i have tokyo knight as i mentioned before in visual studio code so comments are displayed in gray gonna remove all that comment there okay and that's it so and i think this as well and i don't know yeah and it seems also like uh so yeah i think now we've removed all the comments so if i do command s that does a hot reload and i'm actually going to talk about what the hot reload is but if you've done this then you're good to go i'm going to take that in my notes so we've talked about it now the next topic to talk about here is hot reload versus hot restart now these two are so important for you to understand that i think you should like get this before you continue with the rest of the course and i'm gonna do my best to explain what hot reload and hardware start are if you're for instance coming from a design background where you have for instance figma and you design your um stuff you're you're putting some vectors on the screen you're dragging images and i can go in your figma design and literally observe you as you're doing that so i'm actually looking at your changes you don't have to press any publish button nothing like that even if you're in your drafts i can still follow you and watch you as you're designing now that future is very very much possible in flutter as well however the cost of doing that the same thing that figma does is quite heavy because as i'm changing my code i actually i'm not going to be able to see my changes unless i tell flutter that okay i've made some changes show me them on the screen that is hot reload okay for instance if i go in here and i say flutter demo home page and remove the demo home page from here press command s that's going to save my file which in turn is going to do a hot reload okay so command s you can see this title now was changed from here so it's set it says not flutter demo i'm going to change it back command s hot reload and it's going to say home page now you can also avoid for instance doing command s and just go in here in your visual studio code or android studio and just say hot reload so i can see now that didn't actually do it that was great because i can see a little like blob here you see the circle on this file this in visual studio code is an indicator of a file that has not been saved so so if i save it and it itself is going to do a hot reload so i don't have to actually manually press the hot reload button so save and then you can see the changes immediately applied there however some changes to your code are going to be so big that footwear is not able to resolve the delta from the previous state of the application to the new states and we will come to those changes very difficult to explain them right now but just know that hot reload is usually works in 99 something percent like i'm making up statistics here in most cases hot reload works in that it can show you your latest changes however sometimes your changes may be so drastic and so big and the the calculation of the delta from the previous previous state to the next to the new state may be so big that flutter isn't able to do that so then you will have to do hot reload and then hot reload is here sorry hot restart you will have to do a hot restart sorry about that so there's more differences between them like internally about the state like the state of your application and whether one keeps your state and the other one loses your state so i'm not going to talk about that right now because we haven't even talked about states in flutter so i don't think it makes so much sense to talk about that right now just know that in most cases hot reload displays your latest changes and that and it's sufficient if you just do a command s and save your files but hot restart it will basically kind of like rebuild your application with new states okay so i think i think to be honest with you that's sufficient for now so what we need to do now is to have a look a little bit about at restructuring the code that is created for us by default and as you can see here um i mean we don't really know how these things work right now um you don't even know like in the caption i say material app inside run app and home page widget what does this mean well you don't know that and that's okay i'm not going to like confuse us right now with too much detail but what you'll need to know right now is that let's go in here and i'm gonna bring the logs up what i'm gonna do in here in this build function of my app just go and type print building okay and command s and then you'll see that printed to the screen so every time i'm pressing command s this entire application is being built again and there is a little bit of like a resource hug because as you can see here material application is the entire kind of like a scaffolding entire frame of your application including the bar on top including this white view here and including that badge up there on the top right it's like you are pretty much building things that you don't need to build every time you save this file so it's a little bit of like a a problem of um performance whether you want to do that or not but in this in this uh course i'm just i'm gonna give you some advice on how to make your application also run a little bit faster so to do that what we need to do is just to tell flutter that hey look we don't want to build the entire app every time or the app structure every time we're pressing command s to how to hot reload so your challenge here now is to if i get rid of this what we need to do now is you can see here in the main function which is the root function that flutter calls when it actually runs your application it says okay i'm running an app called my app and if you look at my app the only thing it does it actually creates a material app that's all it does so what you need to do now is to grab this material app so i'm just going to say command x on mac or control x i think on windows and linux grab that and instead of this const my app paste that in there okay and then kill your my app boom like that okay and then do command s and just to make sure everything is working correctly i'm just going to do a hot restart and you can see everything is working as it should so what we did here really was actually let's see my homepage yeah that's fine um yeah so what we have now is just the main function and something called my homepage stateful widget all right so get your code also to this state i'm gonna take in my notes that i've talked about that all right so the next thing we need to talk about is stateless versus stateful now state i mean for me it feels like for me to be able to explain this i need to first explain what a state is uh let's say in here i press this button five times okay and then i go and i say oh i want to change the title of this little label there i'm gonna say you you've instead of you have or yeah let's convert this to double quotes because we're putting a single code in there i'm gonna say you've pushed the button this many times and i'm gonna say command s or control s in windows and linux to hot reload hot reload yeah command s okay and you can see is that you've pushed the button this many times but it kept the number five so if it rebuilt this application or this widget or this thing that you can see on the screen how did it keep keep the state well that is because hot reload is able to sometimes as i mentioned before keep your state and state is just data data usually mutated and created either by the application or the user or both and in this case this is a state that the user is controlling so by pressing the button he or she is increasing this number now it's 10 okay a state full widget it can keep that information so it you see it has something called a counter it's an integer and it keeps hold of that number so and upon this number being changed it can kind of redraw itself so stateful widget is something that is on the screen usually something that you can visibly see such as this screen the white screen you can see here stateful and it can contain data upon who's changing it can redraw itself itself so had we had the same widget as you can see in my home page and it was stateless widget which is available as well you see let's switch it it wouldn't necessarily be able to redraw itself or contain any mutable data i mean even stateless widgets for those who are a bit more familiar with flutter you'll have like value not notifier and builders so even stateless widgets can be redrawn depending on what you're trying to do but they cannot contain mutable variables so that is kind of like the um difference between stateful and stateless so you can see here this is a variable that is not read-only otherwise it would be final so if i make this final you can see it says oh you can't reassign this value to something else so just know that if you see state full widget then it is a widget that contains information that can be changed as the user interacts with the widget or as time goes by or as the widget sees fit however stateless widget is a widget who's who has who doesn't contain any mutable pieces of information and doesn't manage any mutable pieces of information internally okay that's a lot of just just there's a lot of talk i know if you're not comfortable with like if you if you haven't done software development before you may not this may not make any sense to you and i promise you as we go on and of course you're gonna learn more about it so don't worry about it if you didn't get this on the get-go so you can see now let's see um let's talk a little bit about i'm gonna actually tick this in the in my in my notes okay so i can see in my notes that i had um that as part of as part of uh what i was going to explain here i was actually i had planned i can see my notes i had planned in one of the previous captions uh here um as part of this caption i was actually supposed to come completely kill this my home page uh widget and i was supposed to actually create a widget just called home page so let's do that let's just go back into that caption so kill this my home page and now go in here and change this to home page so what we need to do now is to create a very simple home page okay so i'm gonna remove this title from here as well and you can see now we have an error telling us that okay i don't know what home page is now what we need to do is to create a uh actually let me see if i plan to create a stateless yeah stateless widget okay a great shortcut that you need to know in visual studio code and i think it may be available in android studio as well is if you want to create a stateless widget just type stl and you can see it tells you that okay you want to create a stateless widget great okay there it is then you give it the name of home page okay so now you have a home page great and i'm going to do a command s and now you can see this is one of the times that flutter was like okay i don't understand what you're trying to do you change some stuff in this main function and i can't do hot reload so you have to do hot restart so now the screen is kind of gonna be black so now we have what i had planned in the course initially for for this chapter so great let's go now to the next point um so you can see the screen is black here and that's because of this container there is a little container there or something on the screen that you can't really see because it's just black so you could go in here and say there is a color and you can say colors red i just command s and you can see now the screen is red so just know that there is something on the screen but you just can't see it because it's all black so the way to get your application to a point that is actually like presentable to a user you usually have to create something called a scaffold now scaffold as it as its name indicates it's kind of just like the basic building structures of an application that kind of makes it presentable to a user to an average user so even though if you're creating like a graphically intensive application this black background may be completely okay but in most applications when you run them then you'll get then you'll get like a bar on top that tells you like the name of the screen that you're on kind of like the title of a web page and you'll also get some like a status bar on top where as you can see here the status bar is kind of like black with all white icons on top and it will give you like a wide screen where you can interact with your content so we don't have that and in order to create that you have to create something called a scaffold so go to your container here and say scaffold okay now i'm gonna press command s and you'll see all this on then we get this little white screen here and then there's a little tint on our status bar as well so it makes it a little bit more presentable okay so what we need to do now i'll basically see if i've planned to add some bar title in here which i haven't so let's do that right now so for our scaffold we're also going to add an is something called an app bar so go to your scaffold and say app bar and then say i create a new instance of the app bar class all right and in here there's a property called title and as the title say text okay and for the text i'm going to get rid of all this documentation there's excessive amount of documentation here which kind of blocks the screen so and for the text just say register for instance and make it a constant so and put a comma here and a uh comma here as well so you see after you've done that your screen has a beautiful blue bar here with the title of your uh application or the title of your home page and there is a white canvas here for the rest of your content to be displayed so now there are a few things in here which i could jump over but i kind of feel like they're so important to explain that i'm going to do that right now so in flutter every time you have for instance here there is a text you see sorry there is an app bar an app bar if you go into the source code of an app bar let's go a little bit higher you can see it it says i'm a stateful widget all right so app bar in itself is a widget so what we're doing here is saying we have something called a scaffold let's go to scaffold it itself is a stateful widget so we're saying the main widget we're returning from our build function as you can see it should return a widget is a scaffold which is a stateful widget in itself it has a property called app bar an app bar it itself is a stateful widget which in turn has a property called title now the title if you look at the documentation it says title is also widget so let me also make the screen a little bit bigger like this so you see it better so now the title is a widget and we're saying oh we're going to use a text widget if you look at text what it is is a stateless widget it means internally it states or its state can change and it it doesn't have any mutable variables okay oh i didn't want to change that so if you see what we're doing here when in flutter you're just creating widgets everywhere in flutter almost everything is a widget either stateful or stateless and you try to you need to kind of try to stick to stateless widgets as much as you can all right we're going to talk more about stateful and stateless so now that we've added the scaffold and i've explained a little bit about these widgets that were we've created and we've done a command as here just to hot reload the application or this widget uh what we need to do next is to create a login button so let's go and create some sort of a login button and you can see here i've written the caption button on home page in the center to log in or more accurately it could actually be register so i'm going to change that i'm going to say register button and button on the homepage in the center to register okay display the caption to you there to and i'm gonna change my notes here just quickly all right so now your task is to create a button on the screen how do you do that well in scaffold you see the scaffold at the moment it's the owner of that bar on top and it's the owner of this white content here so what you need to do is to go and look at a property called body and body is in itself if i move my mouse over it says okay give me a widget you see and of course i could say well i have no widgets null is also acceptable but in this case we're going to create a button called text button so text button is a widget if you go into source code you'll see it's a text button button style button and that is a state full widget all right so you're basically saying that i'm creating a button and i want to allow the user to do something with it all right so we need to do as you can see there is a little bit of an error here to say that says unpressed is a parameter that you haven't provided to me so we need to tell this button that when this button is pressed it needs to do something and this is a requirement for the text button class that it's telling you well i'm a button what do you want me to do when i'm pressed if you don't press if you don't provide unpressed parameter to me i don't i'm not even a button i could just be a label and that is what this error is all about is saying that if you're creating a button make sure that you handle what happens when the user presses on so in here just type unpressed and i'm just going to get visual studio to complete this code for me you can see it says okay an empty function a function with empty list of parameters so no parameters and then the code in itself is empty at the moment okay so go after the create creation of that function and then you see that there is another that you have to handle that says child you see text button you would say you would probably just assume that oh a text button should have some sort of a string parameter that says what is my text so if we write child here the beauty of flutter is that it says child is a widget so text button doesn't doesn't make any assumptions about what content you want to display on that button what it does it says i need to display some widget anything it could be an image it could be an icon it could be whatever it could be a list of things which is not a good idea to do but you could still do that so um go and create a child widget and now you've learned about the text widget so i'm just gonna say a constant text widget and in here we're just going to say register okay now command s and you'll see now all of a sudden you have a register button there so another cool feature now i want to show you in visual studio and i think it's available also in android stu is that you can go and wrap your widgets with other widgets so instead of for instance saying that i want the text button to be in the center and then you go and create a center if you know it also exists you could do command dot or command dot on mac or control dot in windows and linux and visual studio code on the widget that you want to wrap in some other widget and then you will get this beautiful menu that says you you know you can wrap it with many different things so i'm just going to pronounce a wrap with center so as you can see center is a widget that has a child property all center does is that it tries to center horizontally and vertically it's child inside the available space of the center widget itself the entire available space in this case as you can see is this entire white background so center has access to that entire white background right now because center is the root widget of our body which is the only thing that our scaffold is showing at the moment so center then is able to center align this text button so let's command s and you can see the register button is centered horizontally and vertically in the available space now that i've talked about that i'm going to take it here and what we're going to do here is very very important so what we need to do is we now need to handle when the text button is pressed that we're going register a user with firebase okay now we talked about this when i talked about like uh dart in the previous chapters we talked about synchronous and asynchronous and i'm not gonna go into details about that now registration i'm sorry i'm not going to talk about that in details because we've talked about that in details before so if you need to know about that i think synchronous and asynchronous were probably explained in um i'll have a look at my notes they were explained in chapter number seven so if you haven't watched chapter number seven i strongly suggest that you do that if you don't know what sync and async are um what we need to do now is to tell firebase to register user now registering a user with firebase is an asynchronous task so it's not going to complete immediately so what we need to do now is to tell flutter that the button press is an asynchronous task and all you need to do here is just to put the keyword async in there okay so that is that that's it in my notes i've talked about it now what we need to do is to have a look at this link that i've provided for you um i'm going to close this safari window let me see if i can show you on this screen um other sign-in methods great you can see as i'm displaying here firebase allows you to enable various sign-in methods uh to your for your users so um firebase is not only limited to like google services you can as you can see it can allow you to enable facebook signing for users or apple sign-in twitter or phone number sign-in so there are various methods available for you to enable in your flutter application and in this application we're gonna use email and password sign in and there's like documentation about all of those in this link that i've provided provided to you so i'm not gonna go through the entire contents of this to be honest with you because there are just so much information and we're not interested in all of these but still i believe if you're interested in firebase and firebase authentication which we are going to use in this course it is great if you could just have a look at this link that i provided for you here so what we need to do now is also right i've written here that i need to talk about a little bit about anonymous users you see firebase when you start your application and you kick firebait if firebase you basically start the whole process of firebase you say firebase start firebase is amazing in that on the client side it by default creates something called an anonymous user so if you talk with firebase with your thoughts or application and say who's the current user even if you haven't done anything with firebase before if you haven't configured it or actually you have to configure it which we have already done but if you haven't called any firebase functions before in your application you could just say firebase who's the current user and firebase will just tell you here's a current user it's an anonymous user so that user is pretty much never going to be empty it's never going to be null or nil or whatever you like to call it so or if you're python developer you just call it none so that user is almost never none so just know that firebase has a concept of anonymous users okay i'm just going to take that in my notes that we've talked about it so what we need to do in the next step i'm going to bring the caption up so we have to kind of like speed things up a little bit here because there's so much to talk about um what we need to do here now is just to create two text fields now one for the email and the other one for the password and we are going to then put our button um next to those two text fields so text field one email text field 2 password and then the register button as the third component now if you have components like this that you want to stack vertically one on top of each other and one after each other then you need to use a which is called column all right so what i'm going to do here is go here to the center and kind of like remove that i'm just going to say command dot in mac or control dot in windows on linux and just say remove this widget okay i don't want to center anymore command s results register buttons on top left and what i'm going to do is i'm going to command up again and say wrap with column okay now if you command s you'll not see anything directly on the screen no changes all right but what was created for you is a column widget with children property which is a list of widgets that it can display so the first thing we're gonna do is to create two text fields okay so let me have a look here and just make sure yeah i'm just going to say a text field and another text field okay like that save you'll see two text fields display there so i can actually go in there and start typing something okay like that so now we've created two text fields with a column on the screen i'm going to note that here a ticket in my notes so we've talked about it now what we need to do is grab the text that is displayed in this take these text fields and when you press the register button pass that to firebase okay now you see i'm telling you that when you press the button you need to grab the text inside these text fields but inside this function of onpress you have no access to these text fields okay so you kind of need to pass information from this text field and this text field to a text button and the way to do that is is using something called a text controller so a text or a text editing controller a text editing controller is kind of like a proxy object that you pass to your text field and the text field it writes its current text all the time to that text editing controller and in your text button here then you can say controller text okay so you can then so it's kind of like if your text field is sitting here and your text button is sitting here then you'll have something here in the middle that is your proxy the text editing controller that is grabbing me for latest information from the text field and then your the text button can read that information okay so just know that a text editing controller is kind of like a proxy now that we need to manage some state we need to manage this proxy object then we need to convert our home page to a stateful widget okay so go in here to your home page command dot and say convert to stateful widgets so all of a sudden stateful widget all right so um now what we need to do is to go and create those two text editing controllers so i'm going to go in here go to your home page state here and say late final what do we call them do i have any specific desire here let me see my notes no so there's no desire really for the naming so let's just say late final text thing controller and let's call it here email okay and the other one i'm just gonna say password now in the previous chapters we haven't talked about late what late is this keyword in dark that tells your program that although this print although this variable has no value right now but i promise to assign a value to it before it is used so it's kind of like a it's a contract so late literally means that i'm not ready right now i will do it later i'm not ready to assign a value to this so what we need to do now is to um is to create these values now you need to also know something about stateful widgets now that our homepage state is a stateful widget it will have two amazing amazing two great functions one is called init state i believe and the other one called is disposed now init state is a function that will be called by flutter automatically when it creates your home page so it says okay now you have the ability to create all your variables or your late variables once now whenever this homepage then dies and goes out of the memory or it's trying to go out the memory it will also get a function called dispose so you've said that in the contract i've written that i'm going to provide a value for these emails email and password text editing controllers and the best way to do that is to go into this init state function here and assign those to proper values so i'm just gonna say email email is text editing controller like that okay and i'm gonna do the same thing for the password field now you also need to understand that you after you've created these two you also need to dispose of them all right so go in and overwrite your dispose function and then say email dispose and password so a lot of developers forget to do this especially like newcomers so don't make that mistake so you created the text editing controllers and you're also in charge of disposing them okay now um okay uh so we've done that already after you've created your text editing controllers you need to go to your text fields and assign those controllers to your text field so in here there's a parameter called controller and just say email and for your text field on the second one which is for your password say controller it's password so what is happening now is you hooked this proxy object that sat here this one which is your email or password text editing controller to your text field that is sitting here okay you still haven't hooked it to your text button which is sitting here so this link is kind of broken and we're gonna fix that soon okay take it in the notes that we've talked about that so what we need to do now at the moment if i press command s you will see no visible changes on the screen however there's a little bit of a problem with our text fields as you can see they don't have any hint they don't tell the user what they expect the user to actually enter so what we need to do now is to go and add something to these text fields called a hint a hint is a piece of information provided to the user and usually kind of like very subtle color that tells the user about the information that this text field expects them to enter and that hint will automatically be removed as soon as the user types at least one character on that text field okay so let's go to the first text field and say decoration and i believe it's an input decoration and then say input decoration okay and for the hint there's so much information on the screen we can't see anything and there is a hint text as you can see hints text and it expects a string so in here say please enter or just say enter your email here and you can see it's suggesting this to be a constant so i'm going to make it a constant and a little bit of a comma there as well and you can see now it says enter your email here and copy and paste this decoration as well and put it in the next text field so say that enter your password here so let's enter your email here enter your password here so um let me also make sure that that is correct there and take it in the box so um then if you start typing in those fields you can see that the hints disappears as soon as you type something and if you remove that character then the hint also disappears and the same thing for the password okay so we've now got the groundwork like the base work done here and we need to get through the authentication so when you press this text button here where we need to do authentication and that means we're just going to register for now so what you need to do is you need to import firebase so firebase was our dependency and using the import statement you can actually grab the content that it was created for firebase and bring it into your source code okay so as you can see here we're gonna bring package uh firebase off and firebase off parts okay now command s you don't see any difference on the screen because an import statement doesn't really change the state of your application as such and after the importing we need to i'm going to take it here as well that we've talked about it so what we need to do now is to upon pressing this button where we're going to get your username and password from these text fields so let's say final username or sorry email and i'm going to say the email field text i'm going to say final password is password text we're going to our email and password controllers and grabbing their text which is the latest text that the user entered in those fields okay so after we've done that now you can go and say firebase auth instance and then you will say create user with email and password you can see this is a function that allows you to register or create a user as its name indicates uh with firebase so um i'm gonna do that so as you can see here as well this thing returns a future okay so um so this is this is not nothing that you can just like call and say hey do this now um without actually awaiting on it otherwise it will just say here i am a future i'm something that i will calculate something in the future and by not putting a weight before that call you will only get the instance of future you will not actually get the work that it's doing you will get like a wrapper around the work saying that this is the kind of work i'm gonna do but if you have weight on it it will actually perform the work if that makes any sense so i've explained the weight in that chapter i think also chapter seven or whatever it was when we talked about more advanced topics in dart so please have a look at that chapter as well um after doing that you will see that the return of this is actually future of a user credential so what i'm going to do is i'm going to say final user credential is this and then i'm going to print it user credential okay so command s and just hot restart here just in case because we didn't import so what i'm going to do in enter email here i'm going to say pixelityab.gmail.com and for the password i'm just going to say fubar bass okay so let's bring our console up so we can see what our application prints to the screen and i'm just going to say register which we're going to get an error for right now so and you can see here it says no firebase app default has been created called firebase initialize app so this is i mean this is really good that we're getting this because i actually have planned for us to fix that um but before we go ahead and do that um i should probably explain what this is why this is happening you see firebase there was there was if you remember when we configured it there was a file created here for us called firebase options and it has a lot of code in it and then there's like a configuration here uh that here you see android and for ios as well now what firebase is complaining about is saying that you've created this configuration but you've never actually told me about it so poor firebase so what we need to do now before we actually do the configuration is to fix something that you can immediately see on the screen which is which is incorrect you see foo bar bas is your password it shouldn't be visible to the user so when you're typing it it should be a password field and at the same time this field here you see is is an email field but where is the add sign at sign isn't immediately visible here so you need to tell these text fields to be configured in a specific way so that they're actually suitable for email and password registration fields so i'm going to get rid of this bar on the right oh sorry on the left and what we need to do is to bring up the caption for the next thing for the next topic to talk about talk about first what we're going to do is to make this password text field secure so what you need to do here in your decoration of the password field go in here and say obscure um actually it's not in the decorations right here obscure text it has true and if you press s on that you'll see that your text is now obscure also you need to do a enable suggestions false and then you will also do autocorrect false these are three important properties to provide here now you see enable suggestions is usually like as you're typing in a text field depending on your operating system it will provide you suggestions like this in a password field you don't want to do that you don't want to have any suggestions so that's for enabled suggestions also autocorrect is when you try to type something and you know you all probably know what autocorrect is so i'm not going to explain it so you're disabling autocorrect based on your password password field which makes sense so um now let's go and bring these two properties also to our email field which is here okay and what we're also going to do is to tell it that it is an email it needs an email keyboard so let's go in here and say input or keyboard i think type and it's called text input type i think and then dot email there's the email address so save it now if i then go here you can see there's an ad sign so i can um oh sorry you can't see it so i'm going to do this so you can actually see the that sign so you can see their keyboard here and then there's an ad sign right there okay so that's for that and then suggestions are also disabled so as i type there's no suggestions really for my um text because you don't want suggestions on email fields emails are usually like crazy texts so um or not usually but sometimes so you don't want any suggestions there okay we've done that i wanna take all of these items as done in in my notes now the next thing we need to do is uh to fix that uh initialization of our firebase app so we're gonna do it naively right now so i'm going to go because you see we still have this error so if i if i bring this up clean the errors and then say pixelity a b gmail.com and i say ubar baz i say register we will still get this error that says no if no firebase app is configured okay so what we need to do is to actually register sorry initialize firebase before we do firebase instance create user with email and password so what we need to do then is to go here and say firebase initialize firebase app see what we have there firebase auth instance or initialize app i've actually forgotten the syntax for that so let's see if we actually can learn how to do that by going to our um firebase options initialize you can see it should be done like this and what we need to do then is to import firebase options as it's as it's showing here firebase options and then await firebase.initialize app with this okay so let's let's kind of grab that code and then go into our main guard file and import firebase options so i'm going to go here and say import firebase options and right before we do the registration here i'm gonna do this code that was provided there for us so i'm gonna remove the comments command s and i can still see that firebase isn't imported so we're going to import it by doing import library package firebase core firebase core here what i did here is that i basically took advantage something that's built into visual studio code in order for me to get the import statement automatically so i'm going to do command dot on it and it says okay import this dart file so i'm just gonna take advantage of that why not and you can see that it is imported here firebase core so now that we've done that um i'm gonna press command s my state is preserved in the uh in my phone here and let me bring the logs here clean them and then i'm gonna press the register button boom uh here and we got an error here and it says device unlock initializing all firebase apis and firebase preparing to create blah blah and let's actually see what the error was so it is on handle exception request failed and unreachable host and that is probably because i actually don't have proper internet connection on my phone here so i'm gonna go here and i'm gonna go to settings actually great that you're seeing these errors because these things do happen so and i'm gonna turn wi-fi on so make sure that it's gonna connect to a valid wi-fi here and it connected i'm gonna go back to the application clear the logs oh my god there are so many things displayed there so then what i'm gonna do is i'm gonna repeat the same thing i'm gonna say register now so now we got to the next state that i have prepared that it says you can see in the errors it says configuration not found now what is happening here i'm not taking my notes that we've talked about the other part of the code what is happening here is that we haven't actually told firebase that we are going to take advantage of email and password signing combination as i told you before there are various way for various ways for a firebase to allow us to register a user uh apple login um you can do email and password combination you can do facebook you can do google maybe twitter as well yeah i think twitter was there as well so you need to tell firebase that um we basically want to allow this combination all right so now i've explained that let's bring up safari or your favorite browser maybe chrome and let's go to uh console firebase google.com i'm going to bring my browser on the screen so you can also see it and i'm going to then find our application which was called uh my notes flutter project okay so go to consolefirebase.google.com and find your project that you created in the previous chapter click on it then go to authentication as i as i show you here and let's see uh authentication actually get started and in sign in uh what we need is this email and password combination so go email and password combination and just allow it all right so and then press save and that's it that's all you have to do so i'm gonna grab this screen just kind of bring it to another monitor so you don't see it clean the logs and then say register so you can see now all of a sudden you got user credentials back from firebase so you actually could now um register your application like register a real user with firebase like that is actually magical so i'm gonna click on my notes that i've talked about that so however you see this this is a little bit problematic in that by pressing the button but we're actually initializing an application and then we're doing the create user with email and password what would happen if you had two or three buttons on the screen all needing firebase you can't do firebase initialize app in every single one of them so the solution to this is kind of like initializing your firebase application before you start and start with everything else in your in your on your screen and on your phone so there is good documentation of how to do that and i've actually linked to that so i'm going to bring it here so what we need to do is take advantage of something called widgets flutter binding and what happens to be honest with you here is that firebase it needs some it needs to kick start its process before everything else is rendered on the screen and in order for that to happen it needs to it needs to have some sort of that like the core flutter engine to be in place and so that it can make its call to the core slaughter engine and say that i'm done with my work so in order to do that then you need something called um widgets flutter binding so i'm gonna i'm gonna bring up the um caption for that and i can show you that i'm this is this is the documentation that i'm showing you as of linked there so in our in your void function here um before we actually you see maybe i'm jumping over a little bit but what we're trying to do is to try to fix this issue here that we're awaiting on initialize app on firebase okay so we don't want to do this on the press of a button we actually want to do it somewhere else and in order to be able to do that somewhere else we have to first take care of this widget binding okay so in your main function in here then say um i think we need to say widgets flutter binding dot ensure initialized like that okay and if you want to know more about that i strongly suggest that you read this documentation that i've provided here okay so now that that is in place um now that you've done that do a hot restart okay so you're gonna lose your state here after the hot restart and that's okay i'm gonna take that in my notes that i've talked about that now as you know this initialize app is a future you see it's a future of firebase app now what you need to do is kind of like you want to tell flutter to not build this column before it has finished doing that future and the way to do that is using flutter's future builder widget future builder it takes a future it performs the future and once this future has succeeded or it has failed doing its work it will give you a call back and in that callback it asks you to actually produce a widget you want to display to the user depending on the state of that futures result so it basically instead of you having to do this initialization of firebase every time a user presses the button you say i'm not going to do anything until that is done once that is done or if it errors out let me know then i will give you a widget to display to the user depending on the results okay so what we're gonna do is gonna go to this body which is a column right now command dot and then let's see stream builder we have but we don't have future builder so i'm just gonna say command dot wrap with widget and i'm gonna say future builder okay so i'm gonna build a future as you can see it says okay builder is required so let's put a builder parameter here and if you're like me and you forget these syntaxes you can just control space in visual studio code on mac or command space in linux and windows to get help and then you'll just use this syntax there okay so bring your entire column here you see this until the end of the column without the comma then you remove your child bring that entire thing and put a return here and just place it there okay like that now your future builder um it doesn't have an actual future to come to perform so for its future let's see i wanna say that we've talked about the future builder and what we need to do now is to grab this future from here you see await firebase initialize app and grab that future without the weight remove the weight and put it in the future builders future parameter like that all right command s on a hot restart and you can see nothing has really happened on the screen so you didn't have any difference you don't notice any difference basically so if everything really worked as it should um then what we need to do then is to um if everything is working as expected then we should be able to register users so what i'm going to do here is i'm going to provide the exact same user already registered and then say register and you'll see now we get an error let's see if i can show you there and it says the error is firebase auth email already in use the email or the email address is already in use by another account and that is this part which i'm gonna bring the caption up for you so we've also talked about that all right so the next topic that i want to talk about before we close off and round off this uh chapter is connection states you see we told future builder to perform a future the future was firebase initialize app okay this thing now if you look at the builder what we're returning from it right now is a column but we're completely ignoring the parameters that are coming in here the second parameter that gets passed your builder is something called a snapshot of data type async snapshot as you can see there an async snapshot of an object is the state of that object right now okay so and that object itself is actually the result of your future in this case firebase app so it's just that it didn't understand that this snapshot is an async snapshot of your firebase app but that's okay we don't actually need the firebase app in the snapshot however one thing that you do need in this snapshot is its state you see a future has a start point it has a line where it processes its information and it has an end point it either ends successfully or it fails now the snapshot is your way of getting the results of your future whether it has it started is it processing is it done or did it fail so what we need to do in here as we're waiting for firebase initialize app to do its work we're gonna basically say uh we're loading just tell the user loading and as soon as the snapshot is done then we're gonna say that loading has finished so let's do that let's go in here and say switch snapshot i believe it's called connection state all right and then get help from visual studio code to complete this so i'm going to say add missing case clauses and you can see there are so many different cases right done waiting active and done all right so for none waiting let's let's just say everything else except for done we're gonna return like a text that just says loading so let's say in here we remove all of these okay in the done statement we say return this entire column all the way here right and then we don't need the break because we said return and then we're going to say default default is a special case which is not actually inside that enumeration but is a case that says everything else that i haven't handled and in this case we just say return text loading something like this as a constant okay so i'm gonna heart reload sorry hot restart and the two hours video this is happening so fast that we're not actually seeing the loading but at least we have handled the case that if for instance a user's connection is too slow or their device is too slow when the future has finished they will see this column i'm gonna actually fold it and if this feature hasn't finished yet it's not done then they will see this text offloading all right and by the way this is how you can actually fold and unfold things in visual studio code so fold fold like this unfold all right it's a great way of seeing more of your code so wow a lot of information this this video took an hour kind of like as i expected um so we now have a basic firebase setup we've done our initialization of the application of our firebase we talked about a lot of widgets actually we talked about column column we text talked about text future builder text field container god app bar so many things so this is a lot of content and if you didn't get all of it that's okay we're gonna talk more about these in the upcoming chapters but i strongly suggest that i mean if you're watching this course and if you're just watching it and if you're an advanced developer and you're watching that's completely fine but if you're if you're develop if you're not a developer or if you're a junior developer or someone who doesn't have so much experience with flutter development and you're really trying to learn everything i'm saying here please don't just watch this video go and do this yourself go and write this code pause the video as i'm talking i know i'll talk a little bit fast but that's just to save a little bit of time pause the video write the code as i write it test it as i test it and see the results for yourself because that's how you will learn not just by watching so great we've talked a lot about widgets and firebase configuration and in the next chapter we're going to talk about login screen and also email verification and also clean up our registration screen so without further ado let's just prepare yourself for the next chapter and i'll see you there hello and welcome to chapter 13 of this flutter course in this chapter we're going to talk about the login view in chapter 12 as i can see here sorry about that we talked about the registration flow and we actually talked about quite a lot of things which after after that i i thought maybe we need to kind of like go through them one more time just every now and then talk about those those little widgets that we talked about like a future builder center column text button and we talked also about um text field text editing controller so there were lots of components that we talked about but we got pretty much like a a simple registration flow working it wasn't really a flow actually it was just a simple registration screen i'm saying that it wasn't a flow because it was just a simple screen that didn't lean anywhere that's usually what is called the flow if you have a screen that leads somewhere now in this chapter we're going to talk about login the login view and we're also going to divide the logic that we've created in our current home page and put it into a registration view so we're by the end of this chapter we're gonna have two views one is for the registration the other one is for the login okay so as i've shown you here um we have those logic i mean the registration logic in place now we have to work on login but we also work a little bit on cleaning up the code because usually this i mean as you get more and more comfortable with software development you'll know that you will have like these flows of ideas and then you'll start coding and write your code and then you test it and then after a while you realize oh this got a little bit messy i have to refactor the code so that's what refactoring kind of means like you take what is already there and you kind of make it better make it cleaner more presentable so that's what we're also going to do in this chapter so the first thing we need to do is to create a stateful register view widget okay so as you can see here this will be used as the base of our register view so let me go and bring some stuff that we're going to need in this chapter the first one is my scr i bring it to the screen so you'll see it as well and scr cpy we set it up in one of the previous chapters so you should be comfortable with that already um i'm going to go to go to our app here which is the register view that we created gonna bring my face to the right so we'll see a bit more of the content on the screen and then i'm also going to bring up visual studio code which is appearing on another screen right now but i'll bring it up here so you'll see as well i'm going to increase the size a little bit as well so it becomes easier to see so this is where we lift things um let me bring up and do the screen like this so this is where we live things we have a home page which at the moment is the register view okay but we need to create a register view like not just a home page it's called the home page so and since we need a stateful widget we're going to use a shortcut in visual studio code to create a stateful widget for us and that is with s t f as in state full so if you want to create a stateless widget you'd say stl okay so stf and in here we're going to call it what should we say register view like that all right so this will be as i've mentioned here this will be the base of our this will be the base of our registration view all the code for register will appear here i'm sorry that i'm looking here just to make sure that i'm basically going through my notes i have very detailed notes here and just making sure that you get all the information that i plan for you to get so if you see me looking here it's just because i'm looking at the notes to ensure that um so now that we've created register view at the moment it doesn't have anything so it's just a container and the default color for containers and background is black so let's go to our register view here so let's go to our main function here and as you can see at the moment we're returning home page as the home and what we're going to do here is just to say instead of that return register view okay and that is it's very possible we will get a problem here and you can see nothing is changing because i'm changing something inside the main and that isn't affected really by a hot reload so we have to hot restart so i'm gonna go how to restart here and you can see now the screen is black so um that part is basically done so what we'll have to do here now is to rename our home page to our login view actually so we have a new registration view which we're going to write the code for or actually place the code from the previous home page into register view and we also need the home page to be renamed so it's very some i mean there's lots of renaming putting things here and there but we're just playing with some names basically here so the next thing you need to do is to go to your home page which is here and rename it one way to do that visual studio code is to right click on it and just say rename symbol or i believe it's also command f2 or actually for me it's f2 if two does the renaming but on a macbook pro for instance you don't you can't just press f2 because f2 has another function so what you'll need to do is to press function keyboard keep key on your keyboard and then press f2 that will bring up the rename dialog or you could just right click here and just say rename symbol which does the same thing so rename your home page to login view okay all right so we have login view here now um i'm gonna take it that we've done the rename um you see right now all we've been doing here is just to like write our code write everything in main dart but this is this is not a not the right way of doing things especially as your projects get bigger you need to make sure that you're you're taking the responsibility to also make sure that your code is readable and the structure of your project is understandable by others who may also be working on the same project now chances are that if you're watching this course that you will be the only person working on the source code so you won't have anybody else looking at your code even though that you may be the only person looking at the code and working with it you still will need to from time and time come back to the project fix some stuff add some stuff remove some stuff so even if you're the only person working with it you will need a clean source code to look at so if you come back to the source code after a month and you start to add more and more stuff to this main dart file after a while it will just get out of control so you'll need to also do refactoring on your code just to ensure that it is in a clean state so what we're going to do is to bring up our project browser here as you can see we're inside lib and then there's a file called main dart what we need to do here is to move our login view into its own file and you can see here i've written that we're going to move it into lib views login view this file doesn't exist at the moment so you'll need to create it what you'll do here i mean in visual studio code there's a great trick that you can do that it can create a file on all the intermediate folders as well so instead of going here and say new folder to create this views folder and then inside there i create a login view what you'll need to do just say new file and then type the entire path in there so just say views and then slash login view dot dart and this will create the views folder for you so it's great um so what i'll need to do here is to take our login views code as you can see here as we had here class login view and then bring all that code into this new login view file that we just created okay so i'm gonna get this out of the way here and just paste it all right and that's okay we're getting a lot of errors here and the reason behind that is i mean we haven't talked about import statements so much before but import statement is a way for you as a programmer to bring in code written by others whether it is the flutter team at google or whether it is a third party third-party dependency and tell your flutter project where those pieces of code are and at the moment i mean if you're not coming from a software engineering background you're not familiar with imports this is um i mean the closest analogy that i can find is as if for instance in figma you've created um you're trying to create an instance of a design that you've already created but figment doesn't know where that instance is so you'll say oh here's a copy of the button instance and then figma is like oh where can i find that button you haven't even created it so then you need to first go create that button or drag it in from another project and put it in your components page and then you can create an instance of it so if you're not into design and figma you may not understand what i just said but what i'm trying to do is just to be as inclusive as possible in this course to make sure anybody who's following this course will try to at least understand bits and pieces of what i'm saying so going back to import what we need to do now is to tell flutter where those pieces of highlighted code are and one thing to do in visual studio code which can help you greatly if you're trying to go around this writing things by hand is just to do command on mac or control on linux and windows hold down command or control depending on your operating system and press dot then you will see suggestions here as where those components those missing components may be placed and what you'll need to do here is just to import package flutter material because that's where these components that we're using are actually placed so oops i managed to click the wrong wrong option there so material boom all right i think now almost everything has disappeared all almost every error has disappeared except for these firebase errors so let's go and let's see so let's go in there and say now firebase core import that and also here we need to import minors firebase options okay so i think everything basically is disappeared there's also firebase auth import that as well alright so we're good to go now on this login view however remember this login views code really is not login view i mean if you remember the code that we've written in the previous chapter this login view at the moment it says log view but all it does is register do you remember that we have the text field and even the button that says register so what we need to do now is to drag the code as you can see here from the login view here we need to kind of bring it into the register view okay and our register view at the moment is here you see there so let's go and try to do that a little bit with care okay so grab all this code that is here in the login view here there get dispose in its state and also grab your email and password and member variables from here and cut them so i'm gonna go then in here in the register view state then paste those right before the build function so there we go okay go back to login view dart and you can see that there is a build function here here and i'm going to literally just grab that entire build function including the override and as i can see here the build function ends right there and i'm gonna cut that also okay and i'm gonna go here and replace this override on the um on the what is it called register view and paste that one from before here okay so what all we did here is we made sure that the register view it is indeed the register view and the login view is empty at the moment so what you'll need to do you see there's an error here that says that okay you have a stateful widget for login but it doesn't have any build function so you'll now need to create that build function and of course you could do it by hand but it's i mean it's not really it's not really that good of an idea to write all that code by hand of course in the beginning you may say that oh well i just want to learn the best way to learn is to type and i completely understand that but there are some things like there are limits i also believe like once you've done it once or twice you'll kind of get bored of doing that or you'll get tired of doing that so i actually suggest that for these functions that you're overriding the best way is actually get your editor text editor or ide to complete these things for you so i'm going to go on this error and just say command dot on mac and control dot on linux and windows and say create one missing override okay and in here we just say return okay so that's our login view and you can see here now we have a register view that is right here and then we also have a login view all right so let's go then in our main dart file here i can see that there is a register and let's just actually restart this hot restart okay so we have a register and our login view is completely empty so now um what we need to do basically is kind of like um it's kind of work on our login view because this is this is like the goal of this chapter we need to have a login view and up until this point what we've been doing is kind of like create a register view with all the code in it a separate login view which was our previously previously created registry so i mean this is all a lot of talk just to say that we have a registered view but we don't have a login view and we need to work on login views so if you remember um wow i mean you don't actually have to remember you can look at it here the register view has two fields enter your email here and for your password here and this is this their register v and login are very similar to each other what register view does differently is that it creates this it basically does a call to firebase that says create user with email and password but if you think about it everything else is very similar sorry about that so you need to create you need to make sure in both of them that firebase is initialized you will have two text fields email password and you will have a button one for register and for one for login so what we could do to be honest with you is to now go and copy this code that we got from our login view okay that happens i actually forgot that so let's go and copy this code again from here literally get grab everything from there and put it in our login view like that and change this register button to log in so now we have two copies of the same view basically once it's registered the other one says log in all right so and what we could do is now go to our main dart file here and instead of returning the register view we could just return the login view because we want to work on the login view now okay we have a user registered and now we need to work on login and as a side note if you follow the previous chapter you'll you'll know that we actually did register a a valid user with firebase and what you could do is to go to your firebase console as we could do now just an ad hoc i hadn't planned for this but what we could do say console.firebasegoggle.com ensure that you're logged in with your account then i'm going to go to this uh project that we created mynotes flutter project go in there and then go into authentication and you can actually then see the user that you created using the flutter application that you're actually working on so when you call this function in your in your register view this function firebase os instance create user with email and password that user was indeed created in the firebase console so here you have a user you could also disable this user and do other things but we're just going to leave it like that for now okay so what you need to do now is instead of register view tell your home page to render the login view and you could just type login view and if you just type a login view like that you will get an error of course because login view isn't in scope but i believe visual studio code could actually help with that because you see we haven't imported login view at all so this main dart file doesn't know what login view is exactly the same thing happened here do you remember if we didn't have these imports we got lots of errors saying that they i don't know where this class is so the same thing is happening in this main dart file all right so i believe in visual studio code now i'm kind of improvising but i think if you set login view and just press enter boom it does an import automatically for you and let's see where it is here you see but if you're not comfortable doing that just type login view by hand and do the same thing i showed you before just command dot on mac or controlled up in windows and linux and say import okay so it's going to import it for you now we have the login view and if i press command s or actually we have to do a hot restart you see now there is a login button right here okay so what we'll need to do is as you can see in the caption now that we're working on logging the login view go to your login view and go here where the button is pressed you see text button unpressed what we'll need to do here is to call the a new function on our firebase auth instance instead of create user with email and password we're going to say firebase auth got instance but sign in with email and password and you can see the function signature is very similar to create user with email and password in that it takes two parameters namely email and password both of type string and then what it does return in fact is user credential and do you remember create user with email and password also return user credentials so it's very simple to switch between login and register in that in that sense so grab the sign in with email and password name that's the only thing we're interested in and just paste it here instead of create user okay just gonna save that some reason my scrcpy crashed and i have no idea why so that's okay that wasn't planned what we could do is to go to our and i can see you see it got an aborted so what we could do is to go to our terminal and i'm gonna say scr cpy okay and i'm going to bring it to the screen here so and also if you're if you noticed here we have a login button but the title here still says register so let's go and fix that let's go into the app bar and just say login all right and actually problem is i can also see that my as scrcpy crash also the running of this process this application on that android phone also crashed so there is i mean the flutter instance of this project isn't really running at the moment so what i'll have to do is to go to main dart and say run without debugging so and it's now launching doing a gradle build gradle remember from the previous chapters is for android and if it's using xcode it is for ios all right so it's doing the greater build so if everything goes according to the plan then we should get a login title up there and while this is doing its work i'm going to go to my notes and just ensure that i've talked about the things that i promise i'm going to talk about all right it's installing our application i'm gonna remove the widget inspector and now you can see we have a login on top and that is working as expected all right so as you can see here after the logging call here sign in with email and password we're doing a print now what we could do here is to enter some information of a user that doesn't exist okay so i'm just going to say my personal email and i'm going to say foo bar path and i'm then going to bring up the console here as you'll see the debug console clear it um and i'm going to actually remove or do something like this so you can see the debug console a little bit better in its entirety and i'm going to press the login button all right and then sorry about that so we have now um the next thing that we need to handle as you can see uh i'll perhaps increase the size even more here so you'll see it better when i press the login button excuse me using a user that doesn't exist meaning that we haven't registered that user then we got an error here that says firebase off user not found and that that makes sense actually completely because the we haven't actually done any registration for this user okay so what we could hear what we could do here is to go in here and i'm gonna bring things back up kind of the way they were here all right so here we're recalling this function uh let me decrease the size because it's absolutely ginormous in here signing with email and password um we need to handle a thing called an exception and i don't think we talked about exceptions to be honest with you while i was i was teaching you about dart if you know about exceptions you could just skip through kind of skim through this little bit of the video but if you're if you're not a software development developer from before or software engineer then you may not know what an exception is an exception is when things go wrong and you haven't kind of thought about those things from the beginning so as you can as you for instance if you're if you're working with if you're a software if you're a designer or a product owner haven't done software development before you may have also used other pieces of software and sometimes software crashes just like scr cpy just crashed a few minutes ago that is perhaps probably an exception or an error that the software developers who created scrcpy hadn't counted with so they hadn't counted with that an error might occur in this scenario for instance so not having handled that the application crashes it means that an exception happens and error happens that the developers of that program hadn't accounted for so and this is an exception that you're seeing here in your flutter application so firebase is saying that you're trying to log in with a user that doesn't exist so what do you want to do with it i can't continue after this i don't know what to do so the way to handle exceptions in flutter or in dart actually is using a try catch block so i'm going to bring it here put the entire code for your user credential creation in the try statement as you can see here and then go in here and say catch b in parenthesis for now all right just like that and then i'm just gonna say something that happened in single codes all right so you can see here now we have a try block as indicated here with this line it's all the way from on top to here and then we have a catch block the way try catch works is that it as its name indicates it tries to do the work that you're saying it needs to be done in the trial block should anything bad happen it will go to various catch statements that you can't then place after that try okay so as you saw in the logs this error let's see if we can find it here it was of type firebase auth uh let me see on handle exception but we didn't actually get its type unfortunately so what we could do here is print something bad happen and then print the error itself okay so i'm just going to say clear the logs command s and then i'm going to press the login again sorry here and you can see now it says something bad happened firebase auth user not found and then some information and we could actually say print e run time type and doing that will actually give you information about which class of exception this is because you see as you're working with flutter and as you're working with software generally you're creating software you're writing code different types of exceptions happen and these exceptions have their own identity every exception has its own identity it's the series of classes or different places that it may come from in dart you can pretty much anything can become an error even a text can become an error or enum can become an error so when you come to this catch block as i'll move my mouse over it you can see that here it says i don't even know what this is this is an object so it could be anything but you are actually in the in your cache block you're mostly interested in exceptions that might occur from firebase so since we don't really know what this type is we're gonna print it out to the console and we're gonna have a look at what type it is so let me do a little bit of them how should i do this is this a little bit better arrangement perhaps so you can see what happens yeah perhaps then what i'm going to do command this hot reload and go here press the login button and you'll see that the type of that exception is firebase auth exception all right so what we need to do now is to go to our code and handle firebase auth exceptions not just any exception as we're doing here because we're catching any exception so what we want to do is to catch firebase off exceptions in our cache block all right and a way to do that is i'm going to do this now and i'm going to do like we were doing before get rid of the consoles to see more of the code so what you could do you can have specialized cache blocks in dart and that means that you are not catching everything but you tell dark that look in this particular catch block i'm interested only in exceptions of this type and as you might have guessed that already a try block can be accompanied by more than one catch block this cache block that you can see here is called catch all it catches every exception that might occur in the running of the code inside the try block however if you're interested in specific exceptions in this case firebase auth exception i believe oh i've cleared it but i think it was firebase off exception i'm going to run it again go to the login button and you can see it says firebase off exception so we're interested specifically in that so let's go and say tell dart that we're interested in that i'm just i'm going to say on firebase off exception catch e all right so this is the format of catching specific exceptions you prefix your catch statement with the keyword on and then you write the type the runtime type or the class name of the type of exception that you're interested in handling all right so in this case we said on firebase off the exception catchy and we're gonna remove this catch from there and we're gonna go here actually i don't even have to cut and what you'll need to do in here just say print e code you see save this before i before i tell you what i was going to say after uc let's test this let's say login and you'll see that the code is used or not found so now that we told dark that we're specializing in catching exceptions of firebase auth exception then this e is not an object anymore really let's see if we can get some help now it says okay if i can catch exceptions of firebase auth exception then i know that the error that i can pass to you is of that type now that you catching firebase authexception you can go to this code and you see there are different properties that you can read from message code email credential et cetera et cetera okay so we're now interested in the code so as the caption right here shows at the bottom of the screen you'll see that we need to handle e-code equal to user not found all right so let's say if e code is equal to user not found then let's say print user not found like that else e code oh sorry actually we're not going to do it outside kind of like running ahead of myself a little bit there so we have now um e-code user not found then we're just saying print user not found okay i'm going to clear the logs here go back to see our cpy here and i'm just gonna say login and you'll see all it does it says user not found all right so so that's that we haven't really i mean the caption at the bottom left of the screen says handle but depending on your um background you may expect handle to do different things for a software for a seasoned software engineer handle may actually mean that well do something about it okay tell him tell the user like oh i couldn't log in the user couldn't be found or whatever reason just show something to the user and we could do that but at the moment we don't have the capacity to do that we don't really know how to handle that so what we need to do then is to simply say print so we just print it to the screen so this is our handling for now okay it's very simple all it does is just ensures that no exception is thrown to the user's face or that the application doesn't crash okay that was a lot of information um now as the caption here shows in the login view we also need to handle wrong password and i mean as you can see here the e code is a string so anything here could happen that could be defined by string and one other excuse me one of those errors actually is wrong password so let's test that in here let's say else if if the code is not user not found just print something else happened and then print the errors code to the screen okay so i'm going to save this and i'm going to then go here and then actually change this email to an existing email which was the one that i registered and password i believe was foobar or something clickfu bar maybe and i'm going to say login and you can see here it says now something else happened wrong password so that could that could kind of mean that well yeah actually that isn't my password this foo bar was in my password i don't even remember what it was maybe it was full bar bass but that is great it says something else happen an e code and that's exactly what we have to sorry about that and that is exactly what we need to handle here um wrong password so in your else statement say else if e code is wrong password then we're going to say print wrong password okay man is so that's there clear the logs i'm going to say log in and you'll see the message wrong password printed to the screen all right a lot of work we've done quite a lot of work now in the login view but we haven't really put much energy into the register view you see they're very similar in that they do almost the same api calls with the email and password ones that sign in the other ones that's register however in if if we go to our main dart file you'll see in here in our register view we're just calling the api and kind of like hoping for the best there's no try catch statement here okay so what we could do is have a look at how we did it for login we put the api call inside the try block you see what we need to do is to go to main dart and for our register view here register view state do the same thing let's put this in a try block here okay and then just say catch or say on firebase off exception this is i mean i'm not going to explain this again because it's exactly what we did just in the login view i believe firebase authexception didn't really exist in this in this dart file before but that is what visual studio code helped me with as i typed it and pressed enter for auto completion then it must have been imported somewhere or it was probably part of firebase auth dart i believe actually so if i command click on it it goes to firebase auth so that's why i it probably didn't have to import anything because it was already imported as a part of firebase auth okay oh wow that was a lot of information also now that we're working on the register view let's go to our main dar main function here and since we're only seeing the login view let's switch this back to register view and command s but this is not going to change anything as you remember hot reload doesn't have an effect of any changes that you it doesn't have an effect on anything that you're changing the main function remember that you have to hot restart okay so hot restart now we're in the register view and we need to now handle wrong password uh actually no that's not the login sorry about that now we need to handle this weak password so as you're working with uh firebase zoom you will notice that it has its own set of security rules you also can override these security rules later for your server if you want to for instance you can expect or you can say all my users have to have passwords that are 18 um characters long and a mixture of digits and alpha numerical values etcetera etcetera but there are some default security rules set up on firebase for credentials that every user needs to abide by so let's actually have a look at that and let's do a print here and i'm going to say print e code okay and as you'll see in the caption as you are seeing in the caption there is an e code of equal to weak password that needs to be handled so i'm going to go here try to register user with my personal email and the password of a b c all right then i'm going to bring up the console clear the console a little bit i'm going to do this so you'll see it a little bit better then i'm gonna try to register with a password of abc press register what happened here you see the code was weak password and as you'll expect yeah weak password that is too weak a password to even be used anywhere so um so what we need to do here is to handle the weak password error basically i'm gonna take in my notes that i've talked about some other topics of login all right so we'll handle weak password the way we handle the other errors in login view then say if e code is equal to weak password and let's just say print week password okay and we'll say um so that's that's that for now okay and i'm going to just bring up the um debug console again and press the register button one more time now you'll see the information let me bring it so you can actually see it yeah you can actually see it great you can see weak password being printed here all right so that was great now let's go let me bring the let make the screen a little bit bigger the next thing we have to handle is um in this register view as you can see in the caption here you can also get an error called email already in use so if you go to the else statement here again and print e if i try to register with the same email that i registered before this user already exists and if even if i have quite a good password for this user so i'm going to say fubar bass 1029. so we know that the error is not going to be the password like it's actually a good password well better than fubar baz at least and that or abc so i'm just going to say register and do we not get any value here or did i even press the register button is it really registering pixelity a b no i don't think so um oh i hadn't saved the file oops so yeah i haven't saved my changes i'm gonna say register oh now it says email already in use and that is exactly i mean that is pretty much what we have to handle right because we're printing e so um i didn't have to say oh no surprises there so let's handle email already and use so i'm going to copy this email already and use string just exactly as it's mentioned here and i'm going to go to else and say else if e code is equal to that string and then say uh email is already in use okay and then save it there clear the logs press the register button again you can see now it says email is already in use okay so um let me also have a little bit of a look at my notes um i can also i mean to be honest with you in the notes i don't see anywhere that we're really trying to handle uh these errors like actually doing something about them all right so perhaps a better thing to do would be to really like show a message or something to the user and i'm kind of wondering that right now like whether that's a good idea or a bad idea for this chapter and perhaps just doing a print will suffice to be honest with you not entirely sure about that so um let's leave it at that for now okay i'm also gonna go here and make sure that i'm not yeah i'm in do not disturb so let's leave it leave it at that email already use perfect okay let's leave it at that now the next thing that we have to handle it could also write a situation where the user tries to enter an invalid email all right so let's put an else statement here and say print um e code again save it let's go and remove this add sign so it becomes an invalid email and try to press the register button okay now you can see uh you can't actually see now you can see at the bottom in the logs it says invalid email and that is the code for that error so let's handle invalid email now all right so i'm going to go here and say else if e code we call to invalid email then we're going to say print invalid email entered all right and save it so clear the logs tap the register button and now you'll see invalid email entered okay so i mean that's really um all we have to do right now for our error handling and as we're going on i mean to be honest with you i still have a little bit of time to figure out whether we're really going to handle these things by and by that i mean like if we are if we need to display some some error to the user okay and we may need to do that but it is a little bit complicated like depending on how we want to handle it do we want to show like a message to the user do you want to show a toast to the user um or do we want to like display another screen to the user and that's kind of like unclear even to me right now so maybe we'll iron these things out then as we go on in in the upcoming chapters as well so now i can see here that login we've talked about that and what we need to do then in order to be able to carry on with the upcoming chapters is actually to make sure that we are logged in to the application you see we've worked on the register view we've worked on the login view we're trying like so many different combinations here to register new user login so i personally don't know at the moment whether this application firebase instance actually has a logged in user and if you're familiar with like python django or flask or if you're doing nodejs or whatever development like backend development you can be a logged in user but still end up being in a login view so if you send a login login user to a login view doesn't mean that the user isn't logged in instead it means well that user is logged in but may want to log in as a different user so that is the case in our application as well we have a register screen a login view but i personally don't know what the state of the application at the moment is are we logged in or are we not logged in because we're kind of like playing with different views here okay so that's very important now because in the next chapter i can see in chapter 14 we are going to work with um we're working on separating the app initialization from the login and register screens because you can see at the moment we have this future builder that is initializing firebase and it is doing lots of work comes with snapshots stay done blah blah and we're doing the exact same thing in two views login view and the register view so what we need to do is kind of like separate that logic and ensure that we display the correct view depending on yeah what the state of the application is and before we can then continue or start that chapter we kind of need to make sure that the user the current user is logged in all right so let's go to our um main dart here and login logged in views already displayed so i don't really you don't need to worry about this part import login view what you need to do now is to make sure that instead of register view we're displaying the login view and remember now we're saving something changing something in the main function so hot reload isn't going to work so you need to do hot restart so we'll get to that login view and let's then enter valid details here so i'm going to say pixelityab.gmail.com and i think the password was fubar best to be honest i'm going to press the login button all right and there we got the credentials for this user wow that was a lot of information and i understand that um so what we need to work on now i'm going to take some stuff in my notes is as i mentioned we need to for the next chapter i mean we're kind of done with this chapter to be honest we've talked a lot about like exception handling separated the login view from the register view but our register view is still in the main dart we're gonna we're gonna fix that soon but what you need to know to do before you continue with the next chapter and just ensure that you're displaying the login view to the user and that you're actually logging logging in with a valid username and password this ensures that the firebase instance that is running in this application right now is going to cache that information locally on ios is going to cache that information in a secure storage called keychain and on android i think it's called shared preferences or something like that so that information is going to be securely stored now on that telephone which for me is an android telephone right here and when i restart the application whenever if i like shut down my telephone restart the telephone the os come back up that information is already saved on that telephone so my user is logged in all right so just ensure that before you continue with the next chapter that you've registered the user first and that you've logged in with that user from your application so that information is cached inside the application all right good a lot of information in the next chapter we're going to separate the app initialization from the login and the register screens there are only a few steps that we have to do in that chapter so so i don't think that chapter is going to actually be so long so grab a cup of tea coffee whatever you want chocolate or whatever it is and i will see you in the next chapter hello and welcome to chapter number 14 of our flutter course as you saw in the previous chapter we worked on the login view now we have a login view and a register view in place and what you also saw is that we did some very simple error handling for various scenarios such as uh email address already registered weak password um invalid email incorrect password or wrong password i think it was called so now we have two views in place um we have but we have two main issues to address here the registration or the register view that we created still lives in our main.dart file and the other issue is as the caption here displays is that the widgets are doing app initialization if you remember from the code there was this firebase initialization api invocation that we had to do and since the login view and the register view are very similar to each other they're both doing the initialization of firebase what we're going to do in this chapter is separate these um initializations and make them one that's that's the first first thing we need to do so we just have one initialization that's going to happen and what we're also going to do is to bring the register view in its own file so this this chapter is going to be a quick one unlike the other chapters and i think that's kind of refreshing to be honest with you otherwise all chapters are going to be very long and very detailed so with that said let's then um let's then start with the first thing we have to do which is basically to move the register view into views register view okay i'm going to see if i can bring up visual studio code um how we had left it before and i'm going to bring up scrcpy which is my android phone running our flutter application right now so let's do as the caption says here i'm going to make the screen a little bit bigger so you can see better then go to your project uh or explorer here visual studio core if you're using android studio you can go go to the navigator there as well there's a similar one in android studio or if you're using sublime that is exactly the same thing here on the left hand side you can see the project structure then go to lib and then views as we have the login view there let's create a view called register view so right click here and say new file and i'm going to say register mu dot dart okay so then we have to as the question says go back to our main dart file and grab this register view from here group all the register view including its register view state grab all of that cut it in mac you do it with command x and in windows and linux i think you do control x so um i cut that and i'm gonna then bring it into register view here as you saw in the previous chapter doing these things usually cause a lot of headache for for your editor because i mean it's not a headache for you because we can easily fix it for us it's not a problem but it's just the editor that doesn't understand where all these classes are located at so i i've explained this previously in the exact previous chapter before this so i'm not going to explain it again so let's say command dot in visual studio code and then say import material to fix all the stateful widget problems and all the things that all the classes are stored in material dart here in the flotter package okay then we have other problems such as firebase so command dot import firebase core to fix that command dot import firebase options here it's that problem and we will also have to import firebase off i believe and that is also fixed all right so now we have a register view here perfect and um if you see here in our main dart now there are lots of things that are imported which aren't which aren't needed anymore so let's remove those you can see these things are actually you may say okay well how do i find all these problems like there's lots of issues here but had i not come back to the main dart file i wouldn't have seen them and the way to fix that is to actually bring up your problems view here and you'll see that there are lots of problems stated that you can go go and fix those you see print statements are here and then unused imports which you can which you can clean up as well so that's how you can use the problems window i'm going to do that by hand now remove this and remove this so we have a clean void main function here all right i'm gonna do a hot restart just to make sure everything's working as expected then we have the login view here okay so the next thing we need to do now is as the notes i'm actually going to go to my notes and make sure that i have talked about the previous point so the next thing we need to do is to create a dedicated home page that does the app initialization and depending on whether the user is logged in or logged out or if the user is verified or not then it's going to display the correct widget on the screen okay so just to explain that a little bit more is that i mean you i can say that you see in your main function here that when your application run you it runs you're telling it to go to login view but why why are we saying go to login view why are we saying go to register view we have no logic at the moment that says are you logged in then show the login view or if you're not like me and show the registry so that's what we're going to do with our home page okay so imagine the home page kind of being the manager of the different routes that your application can manage so saying that oh if this condition then do this if that condition display the other screen so we need a home page and conveniently named is home page i mean lots of other people may try to call it something else like a route page or whatever but for now we're going to go with homepage because it's just so easy to understand for everyone so let's then go in here and say we want to have a stateless widget stl and we're going to call it home page okay and i'm gonna press escape after that so now we have a stateless widget called home page in our main dart file now what we need to do then after doing that we need to go in our main dart file and instead of saying login view let's just say home page okay and if i press command is remember this is not going to take any effect immediately because hot reload doesn't take into consideration it changes the main function here so you have to do a hot restart so you'll see black screen right now okay so that's that so what we need to do now is to basically have some scaffold in our homepage because we don't want to display just an empty screen to the user okay so let's go in here for our container instead say we return a scaffold talked about scaffold in previous chapters so i'm not going to explain that again and let's go and create an app bar with which we've also talked about title accounts text and say home page okay well command s in mac or control s in linux and windows to save this file and you'll see the changes took effect immediately all right so what do we need in the home page we said that the home page needs to initialize firebase it needs to first do that so that we can get rid of this code in both register view you see this code future builder firebase initialize app and then connection state done blah blah and also we have the exact same code in our login view so there's a lot of code to write in every view that we're gonna develop though this application isn't gonna have so many views maybe six seven views but still we don't wanna do initialize app in every view and do a future builder it's just a lot of code so that's what our homepage is gonna do okay so let's do that uh let's go and grab this code um excuse me let's grab this code with the future builder pretty much maybe the entire build function okay from our login view so go to your login view grab the entire build function until its end which is here this parenthesis okay ending parenthesis close your login view close your register view if you want to then go and replace the entire override of widget build in your home page with that code that you just cut or sorry copied from the login view paste it right here now we we don't want the home page to have any logic that has anything to do with um text fields this homepage is we're going to use it for something a lot more noble so you don't need all the text fields and and all of these columns and uh your text button so go to here where you're creating the column in connection state done and grab that code all the way from return so if i fold it you'll see that that is the entire return and i'm going to actually delete it oops it didn't delete the entire code okay so i'm going to do it by hand from the return all the way down here to where the column ends okay and instead of that column what we're gonna do is just return a text that says okay just like that so if firebase initialization is done it's just gonna say done and let's also change the text here and just call it home all right now that we've done that you can see we still have some problems with firebase not being imported because i deleted those um um imports previously so i'm gonna fix that now command dot on firebase and say import that and command dot on default firebase options or control dot depending on whether on your linux whether if you're on linux or a mac or windows import firebase options all right so now you'll see we have a homepage that just displays the word done here once the connection state of our future which is initialized app of firebase is actually done so hot reload and you'll see hotdog sorry done is also displayed hot done um so uh i'm gonna take that in my notes that i've talked about that all right the next thing we need to do in this chapter is um to make sure that the user is not null and that also the user is verified so under some rare circumstances with firebase such as when you haven't initialized your firebase application using initialize app the user that is stored in the firebase um firebase code or in the instance of firebits running inside your application may actually be null and we've talked about null in uh previous chapters where we talked about dart and it's basics so you can go back to those chapters and watch those so i'm not going to explain what null is again but just quickly null is simply said the absence of a value in this case absence of the user so what we need to do in our application is to ensure that a the user the current user in the application is um non-null meaning that it should be present and also that the user's email should be verified okay so you may be asking why is it important for a user's email to be verified the reason i mean also before i say why is it important for a user's email to be verified maybe let's talk first about what an email verification is and that whether you've already seen it or not so in a lot of services online if for instance you go to a website even if it's a shopping website or amazon or whatever ebay if you say okay i want to register a new user and you say okay here's my email address here's a password of my choosing um once you do that you will be logged into the website they'll say okay if this email doesn't exist already i'm gonna allow you to register this but then you wouldn't really be able to do so much with the website you can search stuff but you probably won't be able to buy things unless until unless you've verified your email and that means that as soon as you register for amazon for instance then it will send you an email to the email that that you chose upon registration and there will usually be a link in that email and say thank you for registering a user at amazon or ebay click on this link to verify your email address you've probably seen emails like that so you could just go to your inbox and search for verify and you'll probably find lots of emails that ask you verify your account with the service so um now let's now that we talked about what email verification is let's talk about why it's important well let's say that i'm a user and i want to use this application that we're developing so i want to score some notes in it then i'll go and and register myself under an email that i don't own all right so let's say then i register my your email address with a password of my choosing since you haven't registered your email address yet with the service icon and ahead of you and register your email address with the service and now i'll just log in remember i'm not logging into your email i'm logging into this application with your email now now i've taken that email so if you then who's the rightful owner of your email address comes to this application and say oh i'm a foobarbaz gmail.com and i want to register an account with this application and it says oops that email address was already taken so you'd be like how is that taken that's my email address so that is the importance of email verification what we need to do in our application is to make sure that whenever someone comes and registers a user using the email address and a password of their choosing then we're gonna send a real email using firebase to that email address and say hey you just registered a user here make sure that you click on this link that says verify blah blah to actually verify your user with our application or with our file with our applications firebase instance that sits on firebase cloud all right so so what we need to do now is to go in here in the connection state done you see let's then check the current user okay let's see if this current user actually is logged into the application so let's say firebase um and then let's say firebase app i believe it's called instance let's see got instance changelog firebase all right let's see if we can actually google that together okay so this is good for you to also see right base flutter get current user we're probably going to end up on some sort of a stack overflow and we'll have a look at how we can actually retrieve the current user as you can see the response here is from a user whose username is quite dissu kurt jr i apologize if i'm butching this name but you can see that it's provided here for you that it says firebaseos.instance and using that instance then you can get the current user so let's do the same thing here let's say firebase off dot instance and then current user okay i'm gonna get rid of this screen on the left which which is our project browser and i'm gonna print this statement right here before we return the done text okay so i'll bring up the debug console clear the debug console and i'm going to say command s all right and since we've made a lot of changes here you see we created a home page lots of stuff in here so what we need to do is just do a hot restart basically flutter in this case wasn't able to really understand what we've changed in our home page so there were so many changes that it just couldn't handle so a hot restart is the remedy there now you can see here as we printed the current user i'm going to do this so you can see more of the the output i'm going to bring it up a little bit i'm going to increase the size quite dramatically so you can see it better as well and i'm going to highlight the parts that were actually printed so this is what firebase or this is what the print statement printed out for us and this is user credentials that were created by firebase and if you remember from the previous chapter i said that make sure before you come to this chapter that you have a login user and this is the reason i wanted us to i wanted the firebase instance in our application to already know that you're logged in so that when we print your current user credentials then as you can see it says here's the email address and then there's a property called email verified false and it says are you an anonymous user false and if you remember from one of the earlier chapters when i talked about the firebase setup then an anonymous user is a user who hasn't really logged into the application yet and firebase is intelligent enough to understand that any user who comes to your application who hasn't logged in before or and their login information isn't saved in keychain or shared preferences on android then that user is anonymous anonymous by default so if you didn't take the um last action from the previous chapter and you didn't log into the application with your current user then you will actually be anonymous here so this flag will say true but since we've already done that we've logged into the application then you'll see our credentials being printed to the screen now this is the part that i was interested in which is email verified and it says false so what we're going to do here is to say take the user so we're saying a final user is firebase off instance current user i'm going to decrease the size a little bit here okay and i'm gonna make the screen a little bit bigger so you can see it better and let's go then create an if statement here and let's say that we're gonna say what what have i planned for it let's just say if user is verified email verified then we're going to say print you are a verified user and otherwise we're going to say print you need verify your email first so you see here because i'm so glad that actually we're seeing this error you can see the entire error it says how can i scroll here it says the property email verify can't be unconditionally accessed because the receiver can be null try making the access condition using question mark dot or adding a null check to the target so what this is saying is if you go to this user move your mouse over it uh if i can do that oh no here you'll see that it says user is an optional user so what firebase has done here is saying this current user property that you can see here is an optional user meaning that well if something goes wrong and firebase can't actually calculate your current user for instance if you disable anonymous users which you can actually do then firebase will be said it will be saying oops null user the user is absent i don't know who this user is so that is firebase api telling your application that if you're using my api then you need to handle this case you can't just ask me if the email is verified because the user may actually be null the user may be absent so there was a great suggestion here you saw here that says you can conditionally access that property using the question mark dot syntax so let's do that question mark done but as you do that you see you'll get another problem it says okay you're asking me to compare an optional boolean with an actual boolean because remember your if conditions need to resolve in into a true or false so um so in this case what you can do is to either create something called for instance if an intermediate variable you can say final email verified and you'll say that is equal to user optional access to email verified field or false you see this is the question mark question mark which we've already talked about when we talked about dark basics so what you said here is take the left hand side of this operator of question mark question mark which is a null aware operator you say if the left hand side exists take it otherwise take the value on the right okay so now if you move your mouse over email verify you'll see that it's a boolean all right perfect so you could either do that or get rid of this intermediate variable that you created here and literally just put the exact same code in your if statement and that will work exactly as it did up there so let's just go ahead with that one less line of code one line of code less maybe um all right so if the user's email verified or false is true which means that if the user's email verification could be read as true or false and if you can't use false if the equation then in itself is true then the user is verified otherwise the user isn't verified so let's do command s there let's bring up our console i'm going to change the screen layout a little bit so you can see better and you can see here it says you need to verify your email i actually clean the screen a little bit and command s again so you'll see a little bit less information on screen and you can see our print statement which was here got printed saying that yeah you haven't verified your email and you need to do that first okay a lot of information but maybe less than the other chapters and to be honest with you this is all we have to talk about in this chapter i just wanted to display or and show you that um or actually explain first what email verification is why is it important and that we're we are going to use email verification in our in our application as you'll soon see and how can you actually read that property from a firebase user great that was all for this chapter now the next chapter is going to be a little bit different you may actually expect a continuation of this chapter you would think that we're going to jump right into email verification but i have intentionally actually put a little bit of a pause in our flow because this is something you'll have to do as a software developer sometimes in that if you see something not kind of correct something isn't working right then you'll need to address it as soon as possible and this is something we're going to address in the next chapter the problem here that you may may if you're a seasoned software developer or may not have thought about is that we are just writing code on our computer this code could be easily deleted by a malicious program a virus or if something happens to our computer all this could just go away and you'll lose everything that you've written so if you're not coming from a software engineering background then you may not know what git and github are now i'm not going to scare you to be honest with you this is not something scary but um what we need to do is just to make sure that we have a backup of our code and just that's just common sense like even if you're a designer even if you're a music producer even if you're a soft if if your product owner whoever or product manager you probably know that whatever you're working on needs to be saved somewhere safely so if you have a video file you're not just going to put it on your computer you're probably going to make a backup of it if you're working with figma that that file is already shared in the cloud is sorry not shared it's already stored in the cloud so it's very rarely that you will work on pieces of um documents that are not securely stored in some sort of cloud and even if you're working for instance with a document then nowadays there's also shared like um sorry there are cloud solutions for storing your documents securely in the cloud so um i mean it pretty much almost always when you're working on a user generated document or a source code in this case you'll need to make sure that it's securely stored in the cloud and that's what we're going to do in the next chapter so we're going to talk about git and github we're going to set up our gpg keys or pgp keys how do you want to say it and we're actually going to dive a little bit deep into git and what it actually means and why it is why is it good why do software developers talk a lot about git and as you might know this course well not might you already know this course is about flutter but i couldn't help put this chapter in because i believe if you're not a software developer if you're coming from another background then it is my duty kind of to tell you about git and github and why is it important how to use it how i like to do very simple tasks with getting github so um so let's then prepare ourselves for the next chapter which is going to be a little bit less coding it's not really we're not at all almost not at all going to be working on the source code we're mainly going to work with git and github so with that said i will wrap up this chapter and i'll see you in the next one hello and welcome to chapter 15 of this letter course in previous chapters we talked a lot about setting up our project so we've so far been working a lot with setting up the project and the basics we also created our login and registered views in our flutter application as i was developing this course myself i got to the point that there was a lot of code being written by me and then i needed to make sure that it is stored in a in a place where i can always go back to even if i lose this information on my computer that i can go back to that place and then retrieve that code so um if you're a software developer if you're if you're a seasoned software developer from before and you know what git and github are and you're comfortable using them and you know how to set up for instance your secure keys with gpg then you can safely jump over this chapter but if you're a designer product owner product manager whoever who doesn't know what git and github are or maybe need some help setting those things up then this is a good chapter for you uh otherwise you can just skim quickly over so let's let's talk quickly about what git and github are and why we need them um as i mentioned when you're working with your code for instance as i was while developing this course then you're writing a lot of code which is i mean intrinsically valuable because your time was translated into those pieces of code as you were writing the code you spent some time and energy and effort and wrote the code so it is quite an important piece of information for you just to lose and depending on the type of project you're working on for instance this project it has taken me quite a lot of time to even develop the idea of the project and put it together so while i was while i was putting together the idea of the course and written writing all the bits and pieces that i have to explain in every video i made quite a lot of backups of that of those ideas because had i not done that and had i just put everything in just one piece of paper or something or just even one digital document on my computer had i lost a document then well yeah i would have lost it and i would have had to begin from the absolute beginning and this is the same thing for your code [Music] so you need to use two services called git and github in order to store your code in in a safe place so that you can always retrieve it later so let's talk quickly about what is git and why do you need this um so what you need to know about gitz is that git is a piece of software on your computer that allows you to manage various changes that you make to a code base such as our project at different times keeping track of the date those changes were made the person who made the changes and the changes themselves and also it will be able to provide you the difference between your recent changes and what was already provided in the or what was already committed into this git repository well what a git repository really is is a bucket is an empty bucket initially where there is nothing in there and as you interact with your source code then you'd be like okay now i want to turn this source code that i've written into a bucket so then there's a bucket created around your source code called a git repository which keeps track of all the changes that you're that you're making or anybody else that works on the same source code is making to the code and it will allow you to save snapshots of those changes at at specific times of your choosing if you're a designer of your and you're working with figma for instance figma already automatically saves your work at the times that it sees fit so you never have to press really a save button and also figma if you've seen it and it keeps track it has a version history so you can literally go to figma and say okay i've done my work i want to actually commit my changes in the version history and i want to give it a name most designers don't do that and they legislate must save their work automatically and by that figma just says here's the timeline of your changes at this time you did this at this time you did this so even if you're a designer you're implicitly using something called a version control and which in it in that case is figma but when you're coming to the software development world we're working with your flutter application there is no figma there and you're working with raw code so you're going into visual studio code or sublime or whatever text editor that you're using android studio as an id or whatever then there is no service sitting there and saying oh you made some changes let me let me help you save it in some sort of app or a cloud solution so the system that allows you to do that on your computer is called git so git is a software that allows you to keep track of changes that you're making to source code okay so i can see here that before we continue we're gonna actually talk a little bit about git and so what i'm gonna do here i'm gonna add lib a little bit here and improvise and i'm gonna go here and make the screen a little bit bigger i'm gonna bring up terminal and you don't see it on that screen because it opened on another screen so let me just increase the size and bring it up here so you also see it so i'm gonna go here to my development folder and i'm going to go to my projects and let's think go to make a folder i'm going to say git okay should i call it git or just let's actually create a folder called testing okay let's go into testing then it is an empty folder as you can see for now and what we're going to do is we're going to tell git now which is a software installed on my computer um to tell it that okay all of a sudden i want to turn this empty directory here into something called a repository remember it's going to be a bucket then that keeps track of changes in the current directory now before we continue maybe oh sorry about that maybe you also need to actually install git on your computer if you're not coming from a software development background you probably don't even have git installed on your computer so i'm going to bring up a a browser window here and say install git so if i google install git you will see that there there's like information how you can install git on your computer if you are on a macintosh and you have already installed xcode xcode comes pre pre like pre-packaged with gits already if you're on windows i believe that you actually have to i have a windows machine right here next to me which i use daily i believe for windows you'll have to install git personally like manual so let's say install git windows uh get download package get a time get guys install git oops my ipad for some reason got disconnected here so i'm going to have some difficulty then um let's see now install git on linux okay i believe there is a good package actually for getting it on windows let me go back here installer on windows you can see here just go to i'm going to increase the screen size a little bit as well so you can see it a little bit better here it says go to https get scm com download win so i'm going to go here and it's going to start downloading so i'm just going to say cancel because right now i'm in a macintosh so here is where you can download git and install it on your computer if you are on a windows machine and you have the linux subsystem which i do on my windows machine then you may actually want to download git using see sudo apt um on that linux subsystem but it is possible that the linux subsystem on windows already comes shipped with git so you don't have to do anything i wouldn't be surprised if git was one of the absolute core components that was shipped with linux um so that's for a macintosh and also if you're on a macintosh and you don't have xcode for whatever reason um then you may need to also download git separately so let's go back here and see how you can do that uh if you say mac os here it says there are several ways to install get on mac users probably install the xcode command line tools which we've already done so if you don't have it in slavery it will prompt you to install it so otherwise you can go in here get semcom download mac and then you can do brew install git so if that is what you want to do then you first have to actually install homebrew so go into this link and say homebrew install basically just do as it says here you see there's the command and then go and install git using homebrew and if you're on linux then a sudo apt install git i think maybe you don't even need to have sudo if you're installing for the current user so just apt app is it get or install i forgot but there's information about linux here as well app install yeah get all so yeah i mean i'm assuming you're kind of like on a debian based distribution as well but otherwise there's information here how you can install it otherwise so all right uh that was a lot of information and before we continue i'm just going to try to make sure that i'm connected back to my uh to my laptop to my ipad here because on my ipad i keep hold of all the information that i have to provide to you in some sort of like a chronological order so it is very important for me to actually get my notes up there so i'm going to try to connect to my ipad and yeah there it is okay so now that you've i'm assuming that you've installed git i'm assuming that that is done if you say which git then it's going to tell me in this case that user being get that's where get it installed if you're on windows to be honest with you i don't know the command on windows to know whether it come like git is installed but on windows all you have to do is just to type git and if if you see that it throws an error it says git isn't available either you haven't installed git and if you have installed git maybe git isn't in the current path so you'll have to go and adjust your environment variables in order to get git and is lots of information on the internet so we're not going to focus right now on how to install git exactly because that's going to be like its own course maybe but if you follow the instructions that were provided on the website that i just showed you should be able to get far so i'm assuming now git is is installed on our computer and you can see here we're in a folder called testing so if i say where that testing is you can see that is is right here now what we want to do is to say testing for instance is the project that we're gonna place all our code in okay so there's gonna be information that we're gonna write here in this um in this folder there's gonna be some dart files there's gonna be some png and jpeg files there's gonna be our application icon all that stuff and we want to store this safely so the first thing you may want to do is to to basically tell git that this current directory in itself is a git's repository so the bucket remember the bucket is going to wrap itself around the directory so if i get the contents of this directory at the moment you can see that it's completely empty but if you want to create a git bucket or a git repository around this directory all you have to say is just to say git init dots okay you'll see here now it says that initialize amt git repository in this folder so now if i get the contents of this folder you'll see that there is a new directory called dot git and dot git directory is where git basically keeps track of its internal like the changes to this directory and like what you save when you save it who is it that saved the work etc so now that you've done that now you've created a git repository basically around this empty directory you can issue various diff git commands such as its status this will give you the current status on this um on this uh directory and you can see here as soon as we created a git repository with git in it all of a sudden my terminal changed my prompt here and said that all of a sudden testing is not just testing anymore but it's actually a git directory and we're on a branch called main now i don't want to talk about branches right now but just know that there are um yeah let's just not talk about branches right now because i'm planning to do that a little bit later so so but what we are going to talk about is this little message here that says no commits yet now in git whenever you're working um git doesn't just save your work automatically you need to tell git to save your work and those points where you save your work there are call commits it commits as its name indicates is you committing your work you say i committed to this and i want to save it and that's i mean it could be called save but save is maybe um it could be uh like read as kind of more like a verb like oh am i gonna save it now or what is it but if i say here's my commit then it could be a little bit easier to infer that oh it's a piece of information that you've saved and you've committed to so i think maybe that's the reason it's called the committee i'm not sure so those commits are points of time where a person that has access to this repository saved their work okay so just remember that that is a commit and if we see here the status says no commits yet because there was literally nothing that you told get to save now what we're going to do is to open up visual studio code so i'm going to bring up you just to studio code here and you can see it's an empty folder and i'm gonna create a file here and let's just call um let's call this um info.txt so just text file okay so here's an empty file and i'm just gonna type hello in here increase the size a little bit as well so you can see better so now if i say git status here you can see all of a sudden it doesn't say no commits yet it it well basically it says dad but it also says on track files and it puts the info text right here now let me then explain what attract file and on track file is a track file is a file that you've told git about before so it it's tracking the changes being made to that file on track file is a file that you have not told yet before about so it says oh here's a file you're doing something with it but i'm not gonna even look at it i'm not gonna keep track of it because you don't you didn't tell me to do so so and things um i mean yeah a file basically can be in three states in git right now you've learned two of them either tracked or on track but it could also be in another state that i will show you soon so now you can see there's a message here that it says let me bring actually the terminal a little bit up here so you can see the terminal in its entirety it says use git add and then the name of the file in order to include what will be committed so let's do that i'm just going to say git add info txt and now i'm going to say git status and all of a sudden you'll see that get understood that here's a new file you're committing committing this file called info text but you can see that it still says you haven't committed anything but it says changes to be committed and all of a sudden this file is green remember i said a file can be in three states on tracked which means git doesn't know about it tracked which means it does know about it or it could be staged so if you see here this file is green and it says changes to be committed so stage is where you have made changes to a file and you've told git that you want to commit it but you haven't committed it yet now you may be asking okay why would i have files that aren't going to be committed in some projects if you have some information for instance if you're working with 10 other developers and you're making some tests and you're writing some code in the in the directory where your source code is placed at but you don't you're not really ready with that file yet you don't want to commit it into a branch where everyone else sees then you could say oh i'm not going to commit this it is not staged file i'm not even ready for staging it and putting it into the commit so in that case you're not going to add it to the staging area okay so remember that now that you've you've done that you just said git add you can commit it and a commit literally means that you're going to save this work in git okay and the way to do that is using git commits and then you will provide a message using dash m here and then quotation marks okay so here you will write a message that will be appended to your entire commit so what we're going to do here says let's just say add new info txt file for fun okay and then i'm just going to press enter and see here it says one file change and one insertions and it will say that yeah it has created this file okay so i'm gonna clear my uh terminal now and we're gonna do git status all of a sudden that message that about no commits yet disappeared and all this is is that is that you're on a branch called main and there's nothing to commit okay so what do you do then if you want to see the commit that you just made like if you want to see okay what are all the comments that were made then in that case you can say git log and git blog will display all the all the commits that were made and who they were made by and you will also be able to see the date that were made and the commit message do you remember we said git commit dash m so that was the message provided in the get command and then saved in the repository okay so that is the message and that's the email of the person who basically did that commit now i jumped over a little bit here and um and to be honest with you that was i didn't really think about that some people if you're installing git then you're not going to have all this information already set up like who you are and there's information about how you configured it and how you tell get who you are and what your name is etc and that is using a command called git config and global for instance but you could actually read about read about that online so just say git config and then you will get a lot of information about how to do that so but just know that git is such a big world that if i want to explain everything about git we could have a course that is already 30 hours just talking about git so just know that there's constraints for on me to explain like the absolute basics of get to you in order for us to be able to use git in this course for this particular use case so i'm gonna just focus on those things okay so um now that you know how to commit i think you're you're like very you're in good place to start learning more about git and the thing you may want to know so which we're not going to use in our in this course is branch using git and why you'll need them now git is a is a piece of software that allows groups of people work on the same piece of code without losing their changes now if you're for instance from a design background if you're working with figma if i go into the design file that you you've shared with me as an observer i cannot make any changes so i can only observe you and i can just like export assets uh or even if you're using um a zeppelin it's the same thing you can so someone some designer sitting with sketch for instance and then they're exporting the work into zeppelin and then you as an observer you're you're exporting that information from zeppelin but you can't make any changes to the source however with git when you share your information for like your git repository with someone else they can also make commits to it as you'll see soon we're going to use github for that so um then basically you need to make sure that every person is identified correctly and then they have for instance they that they have configured get in the right way and sometimes i mean we're talking about branches so sometimes these people don't want to affect what you are doing in this main branch so just imagine and a branch is more like a train line like your train is going there and maybe some some places your friends want to visit a town in the city that you hadn't planned so they get off the train they go on another train line and at the end you will meet so at that point you can see that they branched out into their own branch and that is like the concept of branches in git as well so sometimes when you're working with other developers they may want to branch out into their own branches on the same source code do some experiments and once they figure out what they actually wanted to do maybe they will save their own work into that branch and then they will bring it back to your branch at the end you will meet at the train station and then they bring the results with them and then you merge together so there's a lot of information about branches how they work in kit but just know that branches are kind of like train lines and right now you're on the main train line going from your city to the destination okay so um but again there's time constraints on this course i can't explain everything about git but if you're interested there's lots of great content available on youtube that you can watch and i'm pretty sure that there's lots and lots of tutorials online as well that you can go and read about as well wow that was a lot of information okay um let's now talk about what github is now github is simply said a cloud service for storing your git repositories so um right now this git repository is sitting on my computer so even if if it is i'm committing my work i'm saving my work there's still no uh traceability from the outside world so no one else is allowed to see this code right now it's sitting right on my computer and for that if i want to share this code with other people and potentially allow them not to read only but also to be able to commit and collaborate with me in the source code then i would be able to share that on a cloud service such as github github has the word git in its name but it's not the same thing as git so git is a software that actually manages all your commands and etc but github is the cloud service that holds on these repositories for you so if you don't have a github account i'm going to help you do that right now so let me close actually no i'm not going to close i'm going to minimize this and minimize perhaps um yeah let's close this one i don't think we're gonna need it so i'm gonna bring up a window here and i'm gonna go here and look at this website github.com all right so what we need here is that for you to create a github account and to do that you'll need to go to this website that i will provide for you right there github.com sign up okay so i'm gonna if i bring up um a browsing window here and say sign up you will see that yeah it won't know that i'm signed in already with my other account and it will ask me to start signing up right here okay so this is like the main window for the sign up of github and this they've done it a little bit comically it kind of like a star wars kind of theme i don't know what you want to call it but here you will go through a few steps in order to create a github account okay so i'm not going to do that simply because i've already done that but in your case we'll just need to go through this provide your email choose a good secure password for your email for your github account and then at the end you will have a simple github account okay as i already have so uh we've talked about already setting up git in the terminal so i'm not gonna talk about that i'm just gonna maybe move this um a little bit up all right now after you've set up github on your uh basically after you set up a github account you will need to set up something called ssh keys now this is a little bit technical but and it is nothing that you can jump over it's not like you can actually commit your work without setting up ssh keys on your computer you can always go to github and actually commit your work right on github itself like you can write some text and then change that text right in the github interface like the web interface so then they will do all of that work for you because they will commit it from kind of like their key their own ssh keys i believe but if you on your computer want to be able to commit your work from your hard disk or your ssc or whatever into github you will need something called ssh key ssh keys are cr crypto cryptograph crypt how should i say it is cryptographically even uh let's see crypt cryptographic no crypt yeah cryptographically i don't know yeah cryptographically signed these are cryptographically signed pieces of signature um that will just kind of like private keys that we worked with when we worked with keychain in one of the previous chapters they allow you to identify yourself as a person or as a committer so i think that does make sense so uh i apologize again for the hiccup of cryptographically it's just because i'm not a native english speaker so you should be expecting these hiccups every now and then at least so an ssh key is a piece of key that is a signature that you as a developer or a committer of code create on your computer and whenever you make a commit and you wanna send that commit then to github then github knows who you are okay so it says okay you are person xyz and you're trying to push your changes into this repository i'm just gonna make sure you have access to everything okay so you need your ssh key set up so what we need to do is to go to github and i'm going to bring up a web browser for you to understand how to set up your ssh keys so let's say github sets up ssh keys and you can see adding a new ssh key to your github account so there is a very very comprehensive guide here on how to set up your ssh keys so you can see that it says um let's see generating a new ssh key and adding it to the ssh agent so this is where you want to go okay so after searching for github as a setup ssh keys make sure that you at the end go to this link generating a new ssh key and adding it to the ssh ssh agent read through this there is very comprehensive guide there are only a few commands that you have to issue in the terminal so do them precisely as as it is specified here okay so after you've done that then what you'll need to do is to add that ssh key i believe into your github account you see as the link provides here adding a new ssh key to your github account so you can see here then it says okay do this command and then go to your github account settings and then go to search and gpg keys and then say new ssh key and then add that information in here okay and then press save and that's it then you have your ssh key all set up and done so these are the two things you'll need to do create an ssh key and then upload the public key into github and again because of constraints on this course i can't explain this like line by line to i'm just providing you the information that you need to know and i kind of expect you to do these things on your own okay um so that is that now we also need to talk about um gpg keys uh and let's actually i think gpg was new privacy what was jpg privacy guard so is a piece of software that you download on your computer you can see is a free software replacement for semantics pgp cryptographic software suit uh it is compliant with rfc blah blah all you need to know about gpg and how we're going to use it in this course is that um where you have your i mean we talked about ssh keys where you have your ssh keys and then you and i know this is a little bit geeky but that's kind of like the nature of this thing anyways and when you sign your commits with your ssh key with your private key and then you push your changes to github and github just verifies okay this is a this commit is coming from someone who has access to this repository when you create your gpg keys and then you sign your commits with the gpg keys then that actually verifies that you are who you say you are so a lot of software developers are still continuing with ssh keys and to be honest with you that's not good enough um [Music] i mean well it it depends kind of on your opinion but in my opinion is not good enough because anybody getting a hold of your ssh keys can literally just do anything they want with your commits and change anything they want but um with the gpg keys you'll ensure that you are who you are and anyone else even if they have hold of like your ssh keys their their commits won't be signed as you so um so let's now talk a little bit and we're going to take some items here and just make sure that we've talked about them about ssh keys now we're going to talk about gpgm where you actually need it so there's a little link here i'm going to open that link here so we can both see it and it says git is cryptographically uh still i this word is a little bit different different for me to say cryptographically secure but it's not foolproof if you're taking work from others on the internet and want to verify that commits are actually from a trusted source git has a few ways to sign and verify work using gpg okay so uh so what you'll need to do is uh you need to set up jpg basically on your computer and i and i believe um if you just say gpg install mac or gpg install windows or whatever then you can come to for instance for i'm using jpg tools on mac and for you can actually install gpg for various operating systems for instance windows or linux so just google gpg and then your operating system is so for instance gpg i can smell as spell if i can smell gpg and download noon pg here and you see so this is like the download tools for windows i believe let's see and you can see here you could use gpg for win full featured windows version of you know pg so all i'm trying to say is just to download the piece of software called gpg for your operating system so whether it's gpg for win or gpg tools for mac os or if it's like for debian uh canoe pc is part of debian okay so it's already maybe built in so you don't have to do anything for your debian based linux operating systems all right so after doing that then you will need to set up gpg for github and i'll provide a link here for you that you can read about says managing commit signature verification and the link i'll open it here so you can see how it looks like and you can see here generating a gpg key so you can first go there and it will help you through the various steps that you need to take in order to create your gpg keys it's very easy it's just a few lines of uh code or a few lines of text that you have to issue in your terminal in order to create your gpg keys okay so after you've done that and you need to make sure to go into this section add a new gpg key we've done that and then you go here to your settings you can see ssh and gpg keys and then the same way you added your ssh keys you'll need to add the gpg key in your github account okay and after you've done that the difference between sshk and a gpg key is kind of like to you need to tell get that you have a gpg key and then it needs to sign your commits with your gpg key okay and that's where you go into this tell get your assigning key and you need to just follow these steps to tell get using the git config global user signing key you see here okay so just follow these steps to be honest with you i don't think you need to associate email with gpg really right now but if you want to you can do that so i'm kind of like assuming that you've already done that for um for your computer and that you've created the ssh key you kind of know a little bit about git you have a github account now you have created your pgp keys and then you have told git about your pdp key so your signature comments are actually signed okay so the next thing we need to do is to now can you see we've been working on our um notes application my notes i think it was the um the project was called my notes here if you remember and um if i say git status here you will see that it says not a git repository and that's kind of a little bit sad because we've written quite a lot of code but we haven't really backed it up in github okay so what we need to do now is to go and create a github repository remember that bucket we need to create one of those buckets for our code so let's go i'm going to create a safari window here or chrome or brave firefox whatever you want to use and i'm going to go to github.com and i'm going to go into repositories here as you can see and i'm going to say new and i'm going to give it the name my notes all right i'm going to increase the size of the window so you see it better for the description i'm going to say my notes flutter application and you can see here that tells you it asks you if you want to create a public public repository or a private repository and the difference here is that if you create a public repository everyone can by default read the content that you're creating usually if if you're if you're not 100 sure what public means create a private repository because usually there's lots of information that you may want to create like a private information with some api keys so you want to probably create a private repository unless you know exactly what you're doing or if you want to for instance um contribute to open source projects and create an open source project from an absolute beginning then you go and create a public but you can always make your private repository public later and you can always make your public repository private later but that doesn't happen that often so it's probably a good idea to create a pr private in the beginning okay then in here add a readme file a readme file is pretty much just a file that will be displayed to whoever goes to your github repository and looks at just the index file of the github repository so you can place some information in there but it's usually a good idea to do that you don't have to but i suggest that you actually do that and then say excuse me and then say add git ignore and we haven't talked about git ignore before but what get ignore is that its name indicates is a file that dictates to get on your computer or on the computer of whoever has cloned your repository about what files should not be committed to your git repository so usually it's a good idea to have a get ignore file and in here for the template just choose dart okay dart okay and in here you don't have to choose license right now because you're probably not going to share this code with anybody as it is right now but you can always add a license later okay so i created a private repository some name uh which is my notes sorry yeah um i actually feel no for the name of the repository i'm going to change it just to lower in case i have no space it's just my notes okay and then i'm going to say create repository boom so as you've done that now you will see that you have a repository here and i mean there's nothing really in it okay so what we need to do now is to you see we have our code here and then we have a repository how do we put this code in there you may think okay i'm going to upload all the files by hand or like go and drag files here you could kind of actually do that but it's not a good idea and so what you need to do is just tell git now all of a sudden that hey this folder here is indeed a git repository remember from what i said before so you need to say git init i'm going to bring up the caption so you know what i'm talking about git init and then you say good and it dot okay all of a sudden this became a repository so if you do get status you see let me see if i can actually change the arrangement on the screen so you'll see more of the screen real estate and perhaps i could even do something like this is that a better idea than just doing this no probably not so this is better uh okay this is a little bit better so you see now it says now that you're a git repository i can see you have a lot of files that you haven't really committed and what we could do then we could say git add all add all these files and folders to my git repository and then i'm going to say git commit with the m as a message my initial commits okay see now if i say git status it says there's nothing to commit i want to kind of push these changes i want to send these changes together but how do i do that because if i say git push see it says oh i don't know where to push these things to so what you need to do now is to go to your github repository and then go to code and then grab this guy from here you see to the code to ssh and then copy this and then go in here and do what it says here git remote ad so i'm going to say git remote add origin it's the name of our remote for instance and now i'm going to add that if i say git push it says okay now that you've done that you still need to tell me that this main branch which is on your local computer is actually mapping to the main branch on github which is right here so you see here's the main branch and we're also on the main branch so you don't have to do this complicated code you could actually say git push you origin head which to me is a little bit cleaner and that will do the same thing for you updates were rejected because the remote contains work that you do not have locally this is usually because it's actually great that we got this i had a plan for this to happen but what is happening here is that you see if i go into this github repository and then i can click on this initial commit here you will see that when i created the repository and we chose all those you know readme file and the and the git ignore file these are files that are literally created on github using github by github and placed inside this repository so that is a commit you see it has its own and it has its own commit id now that commit is sitting there in that bucket over here so there's a commit in its own bucket okay now we have our own computer here with its own bucket and its own commit but all of a sudden we're telling this using that git add command that i said what we're doing is that we're we're making a connection between this local repository and the server repository and saying that any changes have happened here we want to push them over here and when we said git push these changes are rejected because it says oh you're you have changes here and commits and you're putting them in here but your changes your repository here didn't contain the changes that were already there so it's saying that there's a conflict i don't know what you're trying to do are you trying to like replace the contents that were over there with your stuff and to be honest with you that could actually be the case because you see what we did here we have a git ignore file here that was created for us by github and also we have our readme file which we probably actually don't need to be honest with you maybe we don't need that and also they get ignored but if you looked at the changes that were committed committing here if i say um lsla you will see there already is a file here it was called get ignore here you see which was created by flutter when we created our project flutter already added that so let's say cat and with ignore to see its contents and you'll see there's lots of stuff that fluffer has already created for us that says these things need to be ignored so what i'm trying to say is that all these things that exist over here we don't need them really so what you could do is say git push f and i believe that force pushes a bit push u origin head f which force pushes everything okay so i'm going to clear that now and i'm going to go to my notes repository and all of a sudden you see that here is you see and oh we already had a readme file as well so flutter has created a readme file that's that's amazing i didn't know this so i learned something that's pretty cool all right there we go so now we have our code basically pushed [Music] um so that is for our commit that is already placed there i'm gonna just take some items here that i've talked about them um great so that is already done as well pushing so now you have your changes over there okay on github now what we need to talk about is also tagging in this course i'm going to use a feature in git called tags a tag is just as its name indicates it kind of is a label so as you're as you become better and better at software development you'll understand that some places sometimes during your journey as a software developer the code that you wrote means a special thing to you for instance you may say after a whole weekend of work i could finally deliver like the verification screen to my users and that in itself in its essence essence has a special importance is it has a special meaning and you may want to tag it and by tagging it it means that i'm just going to give a special name to this so in the future if i want to go back to that point in time i don't go i don't have to go into my be it log and look at all my commits and see which one was that special commit but i also want to like give it a special name okay and that name is a an annotated tag or a tag that has a message applied to it all right so that is in its essence what tagging is so you're giving a name to your um to your uh work basically so what we need to do now here is to tag our work as step one we've done a lot of steps up to this point but none of them has been so like important that we actually have to commit yet but i think this is important enough now we have a registry screen and a login screen so that we can tag it so the way to create it to create an annotated tag and git you will literally just say git tag okay so let's go in here and say git tag and give it the name of step one all right now you can see if i want to push these tags to the back end sorry to github because those tags don't exist right here right now and what we could do is to say git push tags dash tags and this pushes all those tags to the server which is github in that case and to be honest with you i don't really know here one tag i can see all of a sudden here tags and step one is created there okay so what we could do also is that's after we have our gpg keys all set up we also can confirm that our work is truly signed and if i go to my notes here and then look at this commits um let's see if you can see that information somewhere here can we see all our commits um somehow here if you go to this timeline oh it's not showing me that information right now yeah but anyways you could you could have a look at whether your commits are signed by a little badge which i can't see right now so maybe there's actually something wrong with my pgp key so if you've done all the pgp installation correctly on our computer then you should see all your commits being signed and actually displayed here but with some sort of a badge but i can't unfortunately see that maybe github has changed that interface so that we can't see our verified and badge for our jpg keys yet so all right we talked a lot about gits in this chapter um so i think that's actually quite enough for this chapter and git we've talked almost 15 minutes about get to be honest with you and that's sufficient now that we've got get set up what we're going to use it for in the upcoming chapters is whenever we do something significant that needs to be saved we are going to commit that change and also tag it and send both our commits and our tag to github so that is stored securely in some sort of a cloud storage basically so that's how we're going to use git and github in this course and i thought of it as so important for every software developer to know that i thought if anybody is watching this course who is not a software engineer in front before then you definitely need to know about git and github before you can continue so what we're going to do in the next chapter then is to talk about email verification we've done login register screen is very simple but we haven't done the email verification yet and that's exactly what we're going to do in the next chapter so i'll see you there hello and welcome to chapter 16 of the swata course in the previous chapters we've talked about the login and registration page and also we took a little detour to talk about git and github so now you should have all those things set up so you should also have some sort of an emulator simulator or real device setup so we're testing our application right from visual studio code or android studio or sublime whatever text everyone on those devices um in this chapter we're going to as the caption says here we're going to talk about email verification and um i talked about this in the in one of the previous chapters why we need email verification but the main reason for that is as you can see in the caption here says people can sign up with emails they don't own and that is a little bit of a problem and um the reason why it is a problem is that you might get into a situation actually i can see here my wi-fi is kind of tripping okay it's connected now sorry about that and what could happen is if a user comes in to the application and starts your flutter application on their phone or tablet and then they sign up with an email that they don't own and then i as the rightful owner of that email address come to and download the same application and try to register my email and the applications as well this email address already exists so um so we have a problem here so what we need to make sure is that the p people who register in an email can also verify that they own that email address okay so let's take care of that in this chapter gonna bring up visual studio code or you also bring up the editor of your choice where you're um the editor that you're comfortable with um and i'm just gonna take in my notes that i've talked about that so what we're gonna do here as the first step is to go to our main dart file here right after home page and create a state full widget i believe so i'm going to do that right now so sd remember sdf stateful then we're going to call let me see verify email view all right and in here uh what we're gonna do is just to return a simple scaffold so i'm just gonna say return scaffold for now we're gonna get a cons error here so i'm just gonna put the constant there so um that's for our stateful widget then what we're gonna do is um we are as you can see here as soon as we see that um the email isn't verified here we just say you are sorry that it is verified we say you are a verified user and if you're not verified we just say you need to verify your email first but in both cases what we're doing is that we're just returning a text widget that says done and it's displayed here and so what we need to do here is to if the user is verified in here we're going to say return this otherwise what we need to do is to display this verify email view okay but the way we need to do this right now and we're actually going to fix this quite a lot as we go on but right now i just want to show you how to push a view into the screen now pushing is a concept that i believe came came into like a widespread existence after ios and android became popular in the early days of like 2006 2007 actually was 2007 i think and pushing is where you have a screen and you're seeing that screen and then you press a button or something and another screen just kind of pushes itself on top of the existing screen okay so what we need to do now is to if we see that well you haven't verified your email you want to push this verify email view and a way to do that in um flutter is with something called a navigator and remember this is a little bit problematic the thing that we're gonna do right now is actually gonna cause an error and i will explain all this but for now let's just go go ahead and do this so we will fix things as we go on okay so right here that where we say you need to verify your email first and we can actually see that in the console um here um oh you can't see it because it's hidden by the caption but you can see now it says you need to verify your email first so let's go ahead and push that verify email view onto the screen what i'm going to do i'm going to get rid of this so um make the uh what should i do here should i go back to the same layout so you can see yeah that's probably better so go in here and say navigator off and then you say your build context and then you should say push now push is the function that you're calling and you can see here it acts it says okay give me a route and then you say material routes here um material page route okay and then there's a builder function in here and um like this i will explain all of this soon to you and then in here say verify email view just like that um we have to return all of this and i think we're there's something wrong with all this let's see builder and then we're doing that and then one parenthesis i think is missing is it so this one closes there then there's this one and it needs to be ruined and what is the actual error that's being displayed the return time future dynamic isn't a widget as required okay and uh what we need to do is just to do this and yeah that's fine so let's bring this return done back to where it was and then we remove this print statement from here as well and this print statement from there and make this cons and i'm gonna explain all of this so don't worry about it all right so what is happening here is as you can see sorry about that my throat isn't really working with me today so what is happening here is you see in our future builder here we are expected in the builder function which we are right now in here you see we're always expected to return a widget so that's what the future builder does it is in itself a widget that performs a feature and once that future is done or it errors out or whatever then it calls this builder function and in the builder function it is expected to return that builder function itself is expected to return a widget something to display on the screen okay now your job as a developer who's using the future builder is to actually return a widget in this builder function and that's why we're doing here what we're doing here we're saying if the connection state if the future is done return this text of done otherwise return this text so we have basically fulfilled the contractual um agreement here builder expects a widget we return a widget however we're trying to be clever here in saying that okay we do return done but also we're performing an action which is navigator of this context which is our build context and we haven't talked about build context so much before but you can actually see i mean the documentation isn't so clear maybe it says this class presents a set of methods that can be used from build methods and from but anyways what a build context is is kind of like a packaged bit of information that you can you can use in order to pass data from one widget to the other and it is very useful for for instance if you're using block and we haven't talked about block yet but just know the build context is kind of like a bit of information about the context where your widget is at so in here what we're saying we're saying create a navigator of this context and navigator is just a class for you okay and then when you tell navigator to push something it says okay what do you want me to push on the screen then we say create a material page route to push and you can see that material page route has an argument called builder which in itself expects a widget okay so you need to return a widget in this build function but all we're doing here to be honest with you it's just saying that push a widget on the screen that's all so this is like the format that you need to learn about okay navigator of the context push material page route builder context and then you put your widget in there okay all right that was a lot of information i mean this looks kind of okay at the moment so however there is a problem with it and if you're not careful you can miss that problem and i really always like to bring up my debug console so that i'm aware of all problems that might happen and the problem that you can see on the screen it said on handle exception package flutter widgets navigator dart failed assertion line blah blah in navigator so that there is an error [Music] and um there is actually a github issue for that i can see i've actually linked it there as well but we're going to come to that but just be aware that what we are doing here is not really good it's not a good idea to push something inside a future builder but we're going to do it anyways just so we can fix it later so that you know at least this issue exists and at the same time we achieve what we're trying to do here which is displaying a new widget once a condition is met in this case the user's email is not verified okay all right what we need to do now is fix this up fix our widget up here i'm gonna just take some items in my notes alright so at the moment our uh verify email view it it's it's a completely wide scaffold it doesn't even have an app bar there's nothing in there so what we can do is just to first of all go and create an app bar here so we say app bar and app bar title we've done this before so you should know already the syntax and then the title is just gonna say verify email verify email and i can see appbar title is text i don't even know what i've done wrong here to be honest with the constraint isn't the cons instructor it just means that well okay i have to remove this and i have to make this text const um i mean i'm i'm like moving past these things but you may be a little bit confused if you're not if you haven't done this before you may be confused what i'm doing here let's maybe i should explain actually this what is happening here you see before we started using the app bar in scaffold everything was completely fine dart was completely okay and i said okay i'm gonna accept this as it is what we're telling dart here is that we're creating a scaffold and it is a constant scaffold it means it is we're not actually doing any special configuration that makes this not a constant okay but that's so let's actually go here i'm going to hold down command on my macintosh you can hold down control your linux machine or windows and click on scaffold excuse me and you can see that the initializer that i'm calling here or the constructor that i'm calling here is marked as const here okay but as soon as we put app bar in here and i'm going to click on the same thing again let's see if we can find that initializer scaffold app bar this app bar i can't really seem to find that particular initializer but what is happening essentially here is saying that um what you're trying to do here which is creating an app bar with a text inside here a text widget and an app bar makes this scaffold widget not a constant anymore okay so the first thing you need to do is say okay i understand that that's not a constant anymore remove this constant on scaffold but then you get an error here or well a problem telling that okay you've removed the comms from scaffold but still you could make your code better by making your text a constant because this text scene text widget seems to be a constant all right so i'm going to make that a constant now all right so back to our so i'm going to press command s here is not true and i'm going to hot restart verify email okay and i can see we have yeah it's again we have a problem with hot reload because as soon as we do hot reload then we get this error but this error is simply because of something weird that we're doing in here so if you get error just do hot restart and you should be good to go until we fix this problem okay all right so as you can see in the caption of this chapter what we need to do here is to display a column text and a text button to send the verification email so let's go to the body of our scaffold so i'm just going to say body and let's create a column children and inside the children let's just go and say we have a text and say please verify your email address and that's that and then what we're gonna do in here we're gonna place a text button as well and perhaps what could be better is if i scroll this a little bit up so you can see the code in its entirety then the text button if you remember from the previous chapters it has two very important and required parameters child and on press according to darts analysis tools or flutters analysis tools the child parameter of those widgets or those functions that do accept the child is preferred to always be the last parameter so go ahead and create the unpressed first and then go ahead ahead and create the child so in the child we're going to say text off and send email verification okay and make this text content so dark is happy about that and make this constant as well press command s and don't forget the comma here then hot reload so we can see the results okay so now we have some text in there and then we have a button here that says send email verification okay i'm going to take it in my notes that i've talked about that so we don't miss it um now what we need to do here is upon pressing this button we actually need to send an email verification to the current user okay so what we need is the current user so that comes from let's see if we can find it in our login view and register view we have you see login views or credentials firebase code um let's see actually we got the user right here firebase initialize app and then we were like fire yeah that's how you get your current user firebase auth instance current user okay so i'm going to copy that information from our home page okay and bring it into your verify email view state in the button press right there so this is how you get your user okay now what we need to do is as the caption says here we need to await on the user send email verification so say await user send let's see user send email verification okay so now you can see this is a function and it says it can't be unconditionally invoked and that is because user can be nil or null and it is an optional user so as you've understood from the previous chapters you need to conditionally access this function now be a little bit careful here because this function is a future you see it's a future void so as you know calling a function that returns a future void does not invoke the future except it only tells the function to return the future okay so if you actually want the future to be executed you need to wait on it so if you then say await here you'll see we get an error telling that yeah you can't do asynchronous call calls in this current uh scope that you're at and that is simply because the unpressed function is not marked as asynchronous okay so remember that great so um i'm gonna press command s here we get the error i'm gonna do this hot restart then uh if i'm not mistaken i mean if i bring a browser up let's see if i can bring a browser window here and i'm going to say console.firebase google and let's go to our mynotes flatter project and let's go and have a look at our authentication i can see that there's a user here it says pixelityab.gmail.com for you it's probably gonna say something else hopefully it's gonna say something else so that you haven't registered with my email and what we need to do then is to simply go here and press the send email verification button boom okay so nothing happened on the screen and um i'm going to bring up the right caption here so you know what we're talking about now we want to kind of look at how this email actually looks like so let's see if i can bring up that email without uh without uh i like bringing up all my um other emails and other users because that's kind of like private information so all right so uh let's go ahead and see i'm gonna then bring up this email on the screen so you can see how it looks like so as as that email address you can see here that's my email address or this is the user that is logged in into our application then received an email from firebase which is no reply at mynotesflusterproject.firebaseapp.com okay and it says okay you need to click on this link in order to verify your user so now i'm just going to take in my actions in my notes here that i've talked about that and let's then click on this link to verify our identity and here it says your email has been verified you cannot sign in with your new account great okay so i'm going to close that taking in my notes that i've talked about it um and what we can do here then is just to refresh here and there's nothing really different about this user as you can see so um we're also looking at that user and you can't really i mean at the moment i can't personally see if this user is verified or not so maybe that's something that firebase is going to provide in the future just like a checkbox or something saying or like a yeah just like a check icon saying whether this user is verified or not but you can't see that at the moment in firebase console at least i can't all right a lot of information now let's go to our um talk about this error that we got on the screen and i've provided a little link here which i'm going to click on on a separate screen and then bring it bring it up here on the screen that you can see now if you remember where we pushed this verify email widget on the screen using navigator and then material page route i think it's called and where is it material page right here do you remember then we got this error on handle exception okay and then there's an issue actually for that here on flutter's github repository so as you know flutter is an open source project and is an organization here on github and pretty much everything that they're doing for flutter is under that organization on github so as you can see here it says how to call navigator push in future builder error log and then there's lots of great discussions about like what should be done and etc but just know that for now what you need to know is that you cannot do that without having that error although although things may seem fine in on the screen but as you saw as soon as you do a hot hot reload and then you will have this error also so there is an exception being thrown and we need to handle that all right so after you've looked at that uh github issue and you've gone through the comments you'll understand that that's not the way to do things in flutter at least not for now and um i'm actually gonna take it in my notes so if you see me looking here i'm just making sure that i'm explaining everything to you okay um so what we need to do now is to go and change the way our um our verify email view is created so so instead of us returning you see here what we're doing is that we're in our verify email view what we're returning we're returning an entire scaffold and that is why we're trying to push this screen on our current home home page because we're saying that here's the home page and then there this is the verify email view and it has a scaffold just like the home page does do you remember if you go up to our homepage homepage also has a scaffold and an app bar so what we're pretty much saying right now is that this is the home page and we kind of need to move another page on top of it which pretty much has the same structure it has the app parts etc etc and that is causing the problem because we're pushing something in future builder and we're not allowed to do that so what you need to do now is in order to fix this problem just for now we go and remove the scaffold and in our build function all we're gonna do is just to return the column okay so go on your scaffold here and here and what we're gonna do is we're just gonna say uh let's see if we have a remove functionality here and we don't and that's okay i'm just going to grab this column and i'm going to bring it a little bit up so you can see i'm going to put a comma here hot hot reload so we don't see the ugly error on the screen and grab your column here and without the comma at the end grab that column and in the build function just return that okay instead of your scaffold and a semicolon at the end all right um so that's what we're gonna do now for now we're just gonna return column there and then what we need to do um let me see actually that's what we're gonna do now or is it something that we're gonna do later yeah um so yes we've now changed verify email view and that returns a column now let's go in here you see in here when we see that the user isn't verified uh what we need to do then is to say navigator instead of navigator of we're gonna just return our verify email view in here okay so let me go in here and just say return that as a constant and in here otherwise do that so i'm going to press command s here and a hot reload okay so let's go and see what is happening here so what we're saying is that if user instance current if user email verified then return done otherwise return verify email view so what's happening to be honest with you is that previously where we were pushing an entire screen on the current screen now what we're doing is saying that here is a screen already put this verify emails email views widget that returns that is returned from the build function right inside this current screen's content okay so it's a little bit of a difference instead of pushing a whole new screen we're putting that new screen's contents in our screen all right okay and now we have this and i see now that our app still thinks that we're not verified but what we could do is just to make sure you can see here that um at least we're not getting that ugly error anymore so if i do a hot restart here i can see this email verification and that's a little bit strange to be honest with you because we did verify our user so what i'm going to do is just to ensure that this this phone right now has um internet connection and it does so that user should have been verified and i think we actually did click on the verification email so let me go back here go back to the application and what we could do is just to stop the application from running and then press run without debugging and just to ensure that everything is set up correctly so if everything is working fine then we shouldn't come to verify email view instead we should go to here we should display the done text to the to the user so let's just let's just ensure that that is working as expected before we continue with the next item i can still see this and we could simply put some um poor man debugging in here and just prints the user email like that prints the entire user to the screen command s okay and let's go in here i can see email verified is still false is anonymous false metadata last signing time so it still thinks that i'm not verified so what i'm going to do is i'm going to send an email verification and i'm just going to go to my mail here and let me go here and let's just i'm going to bring up that email and let me just ensure that we can click on that link and it says your email has been verified okay then let's close this and i'm gonna do a hot reload here and to be honest with you i can still see now that we're not verified so let's go in to safari and say um firebase flutter email verified not working email verification let's see if there's something that we're missing uh firebase auth current user and then user null is email verified and i believe that is what we're doing here it this is not hopefully a future is actually a user yeah and in here we're initializing the application so that that should work fine as well and then we're getting the user and then email verified that should also work so um one thing to implement is email verified and initiate function imperiality can be ideal approach to easy for verification with firebase well that's not really the problem here connection state waiting and it could simply be that we need to just try to log in with that user so that it tries to contact firebase again okay so what i'm gonna do here is to as we have planned here let's go and change both the login view and the register view as well so that they don't return an entire scaffold but instead we're gonna make sure that they only return their actual content okay as you can see i put in the caption here that they shouldn't for now return a scaffold um so that's going to be done in the home page so let's go and i can see i have a little bit of them now return a scaffold that's the job of home page so i just fixed our little caption there as well let's go to login view and i'm gonna go here and let's go to your login view here you can see we have firebase initialize app future builder we have all that logic also in both login view and registering we shouldn't be doing that so i'm gonna grab this return column all the way from there and go to all the way where the return column ends grab that then i'm gonna pretty much nuke the entire build function and instead return the column okay so that's our login view and now we have a lot of unused imports i'm going to remove them as well and i'm going to go to our register view and for now as well do the same thing for register view go to your build function in the register view and everything needs to be removed except for the actual content which is the column so grab the column as you can see here nuke the entire build function and just return your call all right so what i'm gonna do here is to fix this email verification issue perhaps what we need to do here is for now let's go in here and turn just comment out all the codes so when the initialization of firebase is done just return your login view so let's say return login view okay as a constant so i'm just gonna press command s and then we come here and i'm going to enter pixelityab gmail.com football baz okay and if you remember from login view if you go back to login view we had this beautiful little thing that printed the user credentials to the screen so that is saved already and i've saved here as well so let's go and enter that information pixel tab at gmail.com and then through bar bas and let me bring up the debug console and kind of change the screen layout so so you see it a little bit better as well i'm going to clear the console and i'm going to press the login button so here now we have the user credential you can see it's printed to the screen and now email verified is set to true so the problem there was that when there's email verification sent firebase as you as a user i mean there's something for me to learn as well so i'm actually grateful that i'm learning as i'm actually teaching so one once what happened here is that we verified an email and that email verification we clicked on the link but firebase doesn't immediately understand that you've as a user have verified your email now so what you need to do you need to ask the user to log in and upon that point it seems like firebase is actually refreshing that data locally as well as contacting firebase backend and getting the latest information from there so just because your user has verified their information doesn't mean that the application is immediately going to understand that so you need to ask the user to log in again okay so i can see here now we were supposed to return the logging view um so i'm going to take some items in my notes just to make sure that i've talked about them and we're returning the login view right now from from our home page so this is something you'll need to do also before we continue to the next chapter all right that was a lot of information and um but for this chapter what we've done pretty much is just to create the uh verify uh email view or what we call it is it called verify verify email view we ensure that it can send an email we clicked on the link in the email and made sure that the user is verified and that's and that all has been working fine um but we still have a lot to work on and as you can see it right now i'm going into the code and manually like returning the screens that i personally want to see or it's important for you to see for instance the login view but if you display login view how is the user able to go from the login view to register if they don't have an account that they can log in with so that's what we're gonna do in the next chapter we're gonna create links between our screens so that a user can go from one screen to the other and then back so um so yeah great job that's it for this chapter and i'll see you in the next one hello and welcome to chapter 17 of the slotted course in the previous chapters we've been working quite a lot with some of the basics of flutter for instance stateful stateless widgets we've been looking at a column we've been looking at text button and many other widgets and kind of trying to get our screens presentable to the user and at the same time we've been working on the functionality of the applications such as logging in registering verifying email etc we have a lot to work on and um we're gonna break it down by first starting to work on the link between the login and the register view as you can see here at the moment we i mean i'm going to bring up the code um the way we left it in the previous chapter as you can see here in the main function sorry in our home page widget and also let me change the um let me change the structure on the uh of the different views on the screen so you can see a little bit better so if i do a hot restart here you can see that um when the connection state is done when the firebase application is initialized i'm displaying the or we're displaying the login view here without basically having the option to go to any other screen from here so if i want to send the user to the register view then i have to change this code right here and say okay now you have to go to register view so that's why we need a link between these two views i'm sorry i'm looking at this screen just because i need to actually ensure that i tick the items that i've already explained so um we need to make sure that when a user is on the login screen even if that's the first screen that we always display to the user which is not but if even if it was we need to be able to let the user to go from the login screen to the registry and also from registry view back to the login screen so that's what we're gonna do in this chapter so as the first item that we have to tackle is to go to our login view and add a button that will send us to the registry so i'm going to open up i'm going to bring it here make the screen a little bit smaller here so let's go to our login view which i can see is actually modified um yeah that's okay actually so and what we need here you can see we have a text button and that is for our login view the login button and as you can see the cache has added text but it's allowing you to send us a registry view so right after this text button let's create a new text button and i'm going to bring it a little bit higher so you can see i'm going to say text button remember uh child parameter always has to be at the la at the it should be the last parameter so i'm going to say unpressed ask visual studio code to complete it for me and then i'm going to say child the text is going to say what should it say should it say not registered yet and we say register here something like this i make it a constant okay and i'm gonna save this and you can see now that we have a little button here that says not registered yet register here okay so that part is done but the button at the moment the way it is right now it's not doing anything so we need to address that but before we can do that we need to talk about named routes you see in the previous exercise or in the previous chapter we use navigator and dot of context and push and then we created a material page route that may have all been kind of like alien to you and you didn't really know what was happening and that's okay you will get to know it more and more as we go through the various chapters in this in this course but what we need to do here is to first talk about what a route is and what a name route is and i've actually put a link to a documentation here for you that we can go i'm going to bring up my web browser and i'm going to create a new window and i'm going to say flutter mean routes which is going to end up in the exact same link that you can see there and it says here in the navig in the navigate to a new screenplay recipe however if you need to navigate to the same screen actually it wasn't such a great description to be honest i was kind of expecting a little bit of better description but maybe i can do that myself instead of you having to look at this and i can see to be honest with you this this webpage is a part of a cookbook which kind of is probably all like linked together so in order for you to understand this page you actually have to go to this link and read that and then see and then this would be the continuation so i just put the link here just so you have it as reference but i'm gonna explain that myself here now if we go back to um where we had the named route let's see uh where did we have the name route when we pushed it it was quite a bit before this if i can undo here so this is something called an anonymous route so sorry about that i said name route but this is an anonymous route so a route is as its name indicates in flutter is it's a journey that has a start and an end so it starts from a view and it ends in a view okay that's a route um however there are two types of routes and you can create in flutter either you do your routes either you go to a new screen to your destination from the current screen without providing any sort of information about what this route actually means to your application so it's an anonymous route you're doing it in line you're not telling flutter about this route beforehand so as the user presses the button or for instance in this case as the user ends up in the home page and the future builder initializes firebase upon the connections they've done meaning that the initialization of firebase is complete then we were pushing the verify email view on the screen and then we fixed it by doing all this code so that was an anonymous route you're doing it in place as the done connection state happens then we were pushing a new route uh in our navigator but a named route is the exact same thing that we write like we were doing before but you tell flutter about that route before so that when your application is created and initialized and the flutter engine starts it knows that there is a route with the name xyz for instance or fubar bass whatever you want to define and it goes to a certain screen okay so that is the difference between an anonymous route and a name route in that as its name indicates a named route is a route that has a name so you tell flutter that associate this particular name as a type of string to this route okay i'm going to take it here in my notes that we've talked about that so what we need to do now is to define two routes for our application one called slash login slash and the other one is called slash register okay so let me just go and ensure that i'm bringing those routes correctly so what i'm going to do here and you need to do as well is to go to your main function and at the moment we have a title for a material app and a theme data and then a home here but what you also have is a parameter called routes okay so let's go and say we want to create these routes and you can see here it says routes its value is a map of string and a builder function for the values of those uh string keys so it's a little bit strange it's a map whose keys are strings and values are functions that take in a build context sorry about that and return a widget so it's a little bit of a it's like maybe a paradigm shift in your head but these things do exist and i've already i've also created my own classes that kind of expect this kind of parameter so let's go into routes and say okay now we have routes as you know as you know this is how we create a map map is a is a list of key value pairs or map entries as they're called in flutter and then what we need to do here is i'm sorry but i'll just move some code around i have three screens here so i kind of have to manage those screens at the same time i'm explaining things so what we're gonna do here is to define two routes slash login all right and remember the value of this of the value of every key inside this routes needs to be a function you see it's a function that returns a widget and it takes a build context inside so in here what we're going to do is say we have a context and we return actually sorry login slash we return the login view all right so we say have a route called slash login slash and when that route is used it returns the login view an instance of the login view now we need to do the exact same thing but for register so i'm going to copy this and here just going to say register and instead return the register view which we haven't imported into our main dart file and you can remedy that by pressing command dot on mac or control dot on windows and linux and then say import register view okay that's that and i'm gonna have a look at my notes a little bit so what we need to do now um i've already explained that okay in log area all right so what we need to do now is to go from login to the register view and as you can see i've explained it here in the caption that this will actually cause an error but we will fix this error as we go forward okay so in this uh register view here sorry in this um in our login view so let's go to the login view we have this button right here and what we need to do is just to ensure that by pressing that we can go to the correct place and i think i brought up the caption and you can see that we need to use navigator of context push named and remove until and this this is kind of a peculiar call because what it essentially does is as you can see right now on the screen we have the login and we basically the way we've created things at the moment is that we have the home view which is a widget and then depending on the state of actually no not depending on anything we're literally just hard coding login view to be returned inside this okay so we have the home widget and then inside this home widget we're inserting the contents of login view so login view and home page are kind of like displayed on top of each other and this home page has the scaffold whereas the login view doesn't have any scaffold and it's just a column at the moment if you remember we can go back to login view so you can see that it's just a column okay so that's the structure currently by doing this command that i'm providing you here navigator of context push name and remove until what is going to happen is that as its name indicates it's going to remove everything before it pushes this new route so is what we're basically saying here is that by pressing the not registered yet button and register here we're going to nuke this screen remove it completely from the screen and replace it by this new widget that we're returning okay so let's go to our login view in this button here into the login view and sorry in the not registered yet button we say navigator of context and remove until here push and remove until push named and remove until and in here now we need to display our register route and we refer to that using its name so let's go and fix that now so we say here slash register and put false there as it is and you can see you can get documentation about this and there's a predicate here that returns returns true or false and it says push the route with the given name onto the navigator and then remove all the previous routes until the predicate returns true and at the moment we're just saying return false meaning return remove everything from the route and just go to the register view so just leave this as false right now okay and this is actually going to cause a problem and you will see that soon i'm going to hot restart just in case and we go here to our login view and i'm going to press the not registered button here and boom and you can see now um that's actually great that we're getting this error this is exactly what i what i'd expected so what is happening here is that we're removing everything that's on the screen and pushing around to the screen that has no scaffold so this is the problem that you can see on the screen that yeah i can't just display a column on the screen without anything around it so we need kind of a scaffold and that is what this caption also is saying at the bottom left of the screen as i'm showing you here i'll check some items in my um screen so as the next thing what we need to do now is to go to our register view which is what we're pushing here and make sure that our register view now has all of a sudden a scaffold all right so let's go to lib here and register view i'm gonna remove this project explorer here at the moment we're returning a column what i'm gonna do is gonna command click on mac or control click on linux and windows and say wrap with widget and then call this widget scaffold and just say scaffold body and for the app bar create a new app bar and for its title say text and this is the register view or just say register with constants okay we're just gonna leave it like that i'm just gonna double check in my notes to make sure that's what i had intended for the register view to actually be called yes i can see that it was called register as well there great so we have that now and you can see now we're in the register view and there is no error i'm gonna do a hot restart and we go here again and now i'm gonna press the not registered yet button and you can see we are going to the register view okay so now we have a good connection between the login view to the register view but there is no connection backwards there's no connection from the register view to the login view and that's exactly what we're going to do now just as we did um i'm going to take some items in my notes as well so what just as we did in um in the login view that i'm going to hot restart so you just uh remember you can be reminded of what we did we had a login view as our login button and we added a new item to go from login to register but also we want to make sure that if you are already registered and you ended up on the screen then you can go back to the login view okay so let's do something similar here in our register view and at the end of the register button here let's create a new one and we say text button and uh on crest gonna get help from visual studio code to create that function signature and then i'm going to say child is a text that says what should we say already registered log in here like this okay as a constant and i comma here so we get the formatting in place and now you can see the register view also has a button that says if you're already registered then log in here and the login view has not registered yet register here so now we have to program this and as you saw in the login view we had this functionality navigator of push name blah blah let's copy that functionality from the login view and bring it into the register view under already registered button there and instead of going to registered main route we're going to go to the login name route okay and then hot hot uh hot reload you don't have to hot restart i'm gonna press this button and actually this is really great and that's the same point that i had here so uh link this okay so i've talked about that i'm going to just take some items um in the in my notes to make sure that i've covered all the grounds that i prepared for covering basically so you can see this is the exact same error that we had in the previous screen um or in the previous situation that our uh register view didn't have a scaffold because we went from login view and to register view and then register we didn't have scaffolds so we created a scaffold here if you remember okay but if you go to the login view you can see the login view still returns a column and the way i mean the reason this has been working so far is that because our home page had a scaffold do you remember here homepage had a scaffold and the contents of login view have have so far just been injected into the body of our home page and that's the reason if you hot restart your application you come to this beautiful home screen it says home and then you have the login view right here okay so what we need now is if you remember from the previous chapter we removed the scaffold from their login and their register and now we're putting them back but i kind of want you to understand the reasoning behind why i'm doing things i don't want you to think that everything is perfect from the beginning because for me at least when things are done perfectly in the beginning i always question like what if this thing wasn't there and i'm just trying to make sure that we remedy these things so you go through the entire journey you see what's wrong and how we can fix it instead of just me presenting to you the exact right way of doing things so from the beginning let's go to our login view and make sure we do the same thing that we did with register view and add a scaffold so let's go in here and add a scaffold so i'm going to write i'm going to click on it sorry i'm going to command and we're going to press command and dot on it on mac or control dot on linux and windows and you say wrap with widget and just say your widget is called scaffold scaffold unfortunately doesn't have a child parameter so it has a body so change that parameter to body and let's create an app bar for it then we say app bar and it has a title and we say const text and in here we just say login okay all right now as you can see i mean we've now added the scaffold and as the top as the caption here is telling you it says about login view is being embedded into home page this isn't good so now what we need to do is to go to the next uh section which is we need to remove now the scaffold from our main dart or from the home page because for right now home page is our login view is being embedded into home page but that isn't really good enough so we can't have login view with its own scaffold being embedded inside a home page that already has a scaffold so uh what we need to do is to remove the scaffold from our homepage uh let's see if we can do that and it doesn't seem like it's working so i'm gonna go and say that i'm gonna grab the future builder okay and this is what you need to also do grab the entire future builder and instead of returning the scaffold just return your future builder just like i'm doing here all right um [Music] there's a lot of information and also let's make sure that our um verify email view also has a scaffold because this is what we need right now we need all our views to have a scaffold so i'm going to embed our verify email views columns as well inside a scaffold so wrap with widget and let's say scaffold there is no child in scaffold remember there is a body and then we say app bar is an app bar a title effect const text and we say verify email something like this okay good now if i command s in order to save all these changes we're gonna get an error hopefully which we didn't and that's also okay it's probably because we actually fixed home page so it doesn't have a scaffold that's why we're not getting the error so that is really good i've also explained that then so let's just make sure that the connection is working between these two screens so login view is there you can see there is no home page any anymore displayed here if you remember from before this refactoring then when we sh when we showed the login view then there was the home pages app bar displayed on the screen but home page right now is just a future builder that returns other things such as a text of loading or the login view and also here i noticed that instead of logging loading what we could do is to display a circular progress indicator this is a great widget if you're if you're just doing some sort of a loading that may not immediately have an end so what circular progress indicator does it just shows like a loading indicator we could actually comment all of this code out and just return the circular progress indicator and comment the switch out as well and then press command s so you actually see how it looks like it's ginormous at the moment because there's no scaffold around it but if you had scaffold everything put in place then you would see the circle progress indicator actually displayed correctly on the screen so let's go back command s so we see the log loadings sorry the login screen or the login view and the connection between those screens is working as well the next thing we need to do is to at the moment you see we have our login view and the register view so they're in their own files but in the main guard file we've kind of forgotten or maybe not forgotten we just haven't had the time to do that we have the verify email view still rightly like it's just displayed or it's coded in the main dart file so what we need to do is just to create an an own file for it and we call it verify email view okay so go to views here and right click on it new file and say verify email view dot dart okay and grab the code from verify email view here and paste it or cut it basically and just place it here and make sure all the imports are in place i've already explained in previous chapters how we need to fix imports so i'm not going to go into so much detail about how imports work and how we should do that because i think if you've already gone through the chapters chronologically then this is like obvious for you how to fix it so it kind of feels like if i try to over explain all these things over and over again the people who are watching this course chronologically from the beginning and they're kind of gonna get bored so in the interest of not boring actual people who are watching things i'm not gonna over explain so there we go that is fixed and also let's make sure that we import firebase off as well so that error goes away save just make sure that hot we do a hot restart as well just make sure everything is working as expected and it does so what we need to do now also in in the interest of uh following through with the plan of being a good software developer what we talked about not in the previous chapter but i think it was in chapter let's see it was in chapter 15 i believe where we talked about git and github now we've done a lot of code things are working great let's commit our code okay so as we had if i bring up the terminal here i'm going to do this so you see a little bit better i'm going to bring up terminal and let's go to our terminal here i can see scrcpy is running in this terminal so i'm going to create a new terminal here and i'm going to just say be it log and you can see we had the initial commit and that was step one all right so because we tagged it as a step one you see here so what we do let's just get git status and we see that we've done a lot of work i'm gonna get add all the files to the staging area remember from the git chapter and then let me also make this a little bit bigger so you can see it better um okay then i'm gonna commit and i'm gonna say git commit step two like this okay um and also actually before we do that i believe we've missed a few things then i just look a little bit in my notes just to make sure that i'm not missing things before we continue if i look at um yeah so what we need to actually there's one thing we missed here at the moment what we're doing is saying that okay just go to the login view but one thing that we've missed is to ensure that we go to the correct correct view okay so what we're gonna do is we say we first get the current user so we say here's the user and if the user is not null here and we put an else statement here as well so if the user is not null then we say okay um if user email verified so and we just say print email is verified or we just return text email is verified something like this okay let's go back to the print so before we actually do all this maybe i should explain why we're doing this so at the moment or before we started with this exercise right here whenever the application was running we were just going directly to the login screen but what we need to do now is to now that we have three screens we have the login view register view and also the verify email view is that what we call it verify email view yeah we need to make sure that we're actually accommodating these various conditions into returning the the correct widget so here we're saying that if the user's email is verified let's then say just say email is verified okay and we can actually return maybe even a um and we'll return something so yeah let's do that so we will return text done something like that okay if the email is verified we just say that your email is verified but the user doesn't see that if the email is not verified we will we will basically return verify email view okay so that's us basically saying that yeah you need to verify your email that's if user is not null now if the user is null then we send you to the login view so let's go in here in the ill statement we say return login view as a constant so i think that should do it to be honest with you return cons return log so we can remove all of this from here boom so let's review it upon firebase initialization being done successfully we are going to check for the current user if there is a user we're gonna check if the email is verified if email is verified right now we're just going to say print email is verified and since we're not returning anything in here the code is going to fall through to line 48 here which in turn then returns just a text done okay so if you have a logged in user sorry if you have a user who's logging into the application and the email is verified all the user is going to see is just a text done all right but if you have a user in the application whose email is not verified that user is going to see the verify email view if you don't have a user with firebase so that user is not logged in then we're going to display the login view all right a lot of information i understand this may be a little bit frustrating so so now i'm going to hot restart and what you can see here is just a very ugly text done displayed on the screen this means the current user in the application is logged in and the email is verified and it is very ugly i understand but you need to also understand the reason why this is ugly at the moment and that is what happens if you do not tell flutter how things need to be rendered and since our home page has a future builder and nothing else surrounding it there is no scaffold there's nothing it's just a text widget that's flutter telling you okay i don't even know how to render things anymore i don't know what theme you're using i don't know the font size i don't know the default font color so that's what happens if you don't surround your widgets with a scaffold or another material widget that knows how to render things okay wow a lot of information again um but i hope you're sticking with me here now that we've done that we can go and commit so let's have it look at our logs and look at the status i'm gonna change the structure or the layout of the screen so you see better and now now we see that after we did git add we've also changed the main dart file with these changes so i'm gonna get at that as well all those changes and i'm gonna say git commit step two okay so now that's gonna be committed and we're also going to push the commit and additionally we need to tag it okay because if you remember if you look at the logs the first commit that we did here it was tagged as step one now we've committed step two but we haven't tagged it so let's go tag it i'm gonna say git tag um step two and then you need to push your tags with bit push dash dash tags and that creates the step two tag as well for you okay i understand that was a lot of information but i hope you could stick with me and go through all these steps so that we are ready basically for the next chapter all right and also before continuing with the next chapter just ensure that you're logged in because in the next chapter we're actually going to work on the log out so i can see also i've planned a lot of information in that chapter for you so there's lots and lots and lots of things to do so it's a very exciting chapter actually the next chapter and but before you continue with that just ensure that you go to the login screen and ensure that you log in with the user and you just see this ugly done button here okay and as i mentioned in the next chapter we're going to talk about displaying a simple interface to the users who are logged in and also allow those logged in users to log out so get some coffee tea if you want to or whatever refreshments you want and i'll see you in the next chapter hello and welcome to chapter 18 of this flutter course in previous chapters we've talked a lot about login and registration views and and we've also talked about integration with firebase we now have pretty much like our login and register view well i don't want to say we've got them down but we have a basic login and a basic registration view um if you remember from the previous chapter we kind of left the application and state that if the application detected that you had um you were a logged in user and that you had a verified email address then we showed kind of like a dirty done text on the screen and i can bring bring the screen up on my android phone here and you see we kind of left it in this state and i'll bring the code up as well so you just get reminded of what we were doing so we left the application in this state that if the user wasn't null meaning that the user was present and that his or her email address was actually verified we simply did a print statement in there and we left it like that meaning that since our builder function of let me actually bring up the right caption as well since the builder function of the future builder requires that you return a widget by moving your mouse over you can actually see that it says required widget you need to return a widget from that function since it requires that what we did is just we put a like a return cons text at the end of all our if statements so if none of these were present there we're still returning a text okay and since that was there and in this user email verified we're not returning a widget then the code falls through to this line meaning that if you're a logged in user and you're verified then we're returning the text off done so we need to kind of um now start because you see okay before i say that sentence now that we are have handled the email verification view so if you're if you're a logged in user but your email isn't verified we displayed it verify email and if you're if you aren't registered meaning that like you don't have a user then we show the login view since we've got those down what we need to do now is to work on the actual main ui of our application because what you can see here that says done this should be the main ui of our application so users who are logged in and their emails are ready are verified should see the main ui of the application so in this chapter we're actually going to work on the main ui of our application and then allow the user to log out from our application as well so i'm just looking at my notes to ensure i'm telling you all the stuff that i plan to tell you so without further ado maybe we could actually get started with that so let's go into our main dart file here and create a new widget so i'm going to bring it up here and we're going to create a new stateful widget called notes view and this notes you just imagine that it is the it is the main ui of the application for people who are logged in okay so as i mentioned before stf to create a stateful widget and then we call it um notes view i believe all right now what we need to do let's see it doesn't even really have a scaffold or anything so maybe that's what we need to do i'm just gonna go here so let's go create a scaffold and an app bar for it all right so we go in here into where we're returning a container at the moment we just say we want a scaffold and for our scaffold we want an app bar and the app bar should just be an app bar with a title of um const text and we just say what should we call it i don't think i've got notes for that to be honest with you let's just call it your notes or something like that i'm gonna actually go and have a look at my notes to see what i've called it in that um where i was actually preparing this course for you and i can see i've written main ui so let's just do that let's just say main ui in here okay so we have a scaffold in there so and it just says main ui and the body is empty at the moment so there is nobody and if you remember from previous chapters when you return a scaffold and an app bar all it does is that it creates kind of like depending on your theme but usually with the light theme it creates a a bluish status bar and an app bar with white text for the app bars title and the rest of the content of the screen is just going to be white so it's kind of like an empty container kind of okay now we have that in place and we are going to go to our uh future builder here in our home page and instead of doing this returning text done we're going to remove that and now we're going to get an error saying that well the case should not complete normally try adding break or return and that's basically it's complaining in this line of code here for me in line 41 it may be another line of code for you so it's saying that well one of the cases of your your like the entire block of code that you're placing in here it doesn't always end with a return and that's exactly right because in the case of user being email verified we're not returning a widget and what we're going to do in here we're just going to say return const to you okay all right um and i'm going to press command s there and now we did a hot uh reload and you can see the main ui of the application and in my notes i can see here that we're going to go and place a little text in our scaffold here and for your app bar we're good to go for the body let's just say const text hello world okay so now we can see the hello world displayed right there i can see i have a lot of notes to be honest with you with this chapter so i'm really making sure that i'm looking at my notes while i'm giving you the content to ensure that you're getting all the information that i plan for you to get so i apologize if i'm looking a lot at my notes it's just to yeah it's just to deliver the best content for you to be honest okay so we've done that hello world now what we need to talk about is um the app bar class and i've provided a link here for you which i'm going to open on my screen and then bring to this screen so you can also see it increase the size a little bit and perhaps also do this layout so you can see it's um the caption as well so you can see for appbar the documentation just says a material design app bar an app bar consists of a toolbar and potentially other widgets so all you need to do really or all you need to know about an app bar is that um it it it is able to display various widgets i mean pretty much everything in flutter is a widget so an app bar isn't an exception and an app bar consists of various components the default app bar allows you to display a title as you can see here in the title by default has its own styling it means that it has its own left and top and bottom margins so by default it's like displayed vertically in the middle of your app bar as you can see in the main ui of our application so pretty much every material component pretty much everything you display on the screen has a theme okay and an app bar has its own theme and it has its own capabilities so what we're going to do the where we're going to use the app bar in the main ui of our application is not only to display a title but it's also to display a um a little button to the far right that the user can click on or tap on in in our case tap on because there'll be indirect users are going to run our application on mobile devices so they're going to tap and if we allowed the our application to be run on desktops then they'd be able to click and maybe even tap on if they're running for for instance um microsoft's what is it called surface book or surface lap tablets so this is what an app bar is as is like the gist of it and there's information here in the documentation you can see here it says there's a leading space and then there's or you can actually put a widget in the leading and then there's a title and then some other actions and these are the things we're actually going to use actions in this um in this section in this chapter of our uh flutter course so you can see here for instance there's actually code on how to configure an app bar with some button you can see you can press the button and then you get a snack bar right here okay so keep this in mind you can have a look at the documentation i really actually suggest that you do that and um and you can you can spend some time reading through the documentation but i don't think you need to get absorbed in the documentation so much but just have a look at the various parts of an app bar and try it for yourself okay so um i can see that i've told you about the documentaries i'm gonna um i'm gonna move past that so that that part is done um and now what i think we need to do um is to talk about uh this print statement and why we were getting an error here you see print if if i if i put a print here and if i say print hello world you usually get information here saying avoid print calls in production code okay so before we move past this because you've probably seen this quite a lot in this course that i've placed print statements and then we can like for instance if i bring up the debug console and just do command s on my mac or control so linux and windows in order to hot reload you'll see let's see actually email verify heart reload i'll restart here oops see i can see that it crashed that's okay so i'm gonna go and bring up scr cpy again and these things do happen and that's completely fine so and i'm gonna need to run the application again because i actually lost my connection with that device but while that is doing its job i'm gonna tell you also about print and versus a log you see uh print is usually called a poor man's debugger in that um if you're not a software developer you probably don't know about even debugging what that means but what debugging is is it essentially is is where there is a problem in your source code but you don't know really where so you try to step through various lines of code in your application and refine what the problem is so um a lot of a lot of times when people don't really either they don't have the time to debug or they believe that the debugger is just too slow they start putting print statements in their application and um by putting print statements in their application they can kind of track where they where the application is going through the various lines of code and if for instance they put a print statement in a place of code where they didn't expect the application to end up and then they'd be like oh okay i ended up in this code block i shouldn't have so let me just check why i ended up here so it's kind of called a poor amount debugging because print is a piece of code that you actually place in your code so sometimes print isn't the desirable thing to do in banking applications for instance you should be extremely careful what you print because these things get logged and you you may think well okay they get logged on that phone uh what is the problem with that the problem with logging things even if it's on the phone is that you you must know that the operating systems android and ios usually like the most popular ones right now they keep track of your lot so these logs are actually stored in a place on the operating system so you can actually read them back later so there is a buffer so this information that your application may be printing to the console isn't completely private except that it is stored on the phone even if it's for a short while while it gets replaced by a new buffer if your phone ends up in the wrong hands someone can actually get a hold of your lock so imagine a banking application logs your like a login information username password all that detail and even if it's only for that application you may think but someone else it may actually end up in the wrong hand so that's what this information is telling you avoid print calls in production code okay so there is another way of doing this um instead of doing prints you can actually use log in your in your code and we're gonna i believe we're actually going to talk about in this chapter i think we're gonna talk about logging so let me have a look here in my notes um yes we're actually going to talk about logging instead of printing so just keep that in mind that there's a better way of doing print statements if if they're if that's what you want to do if that's what you want to see on the console so we're gonna fix that soon and this is you see hello world information that was printed by this print statement okay so sorry about that that was just a little detour but i i thought it was necessary to tell you especially if you haven't done software development before okay we've done the return notes view in the home page we shouldn't have any print in the home page and you can see this is our home page right now and we don't have any print statements let me change the view a little bit all right so um so what i'm gonna now describe to you is that we need a an enumeration that describes our various um app bar items that the user can click on you see when we create our app bar and this app bar will in itself be able to display something called a pop-up all right so i haven't shown you how this is going to work by the end of this chapter so it may be a little bit difficult to understand but just imagine that we have our ui here and what we need to achieve in this chapter is to place a little button here with like a dot dot either horizontally or vertically i don't really know what the icon is going to be so some sort of a button here upon pressing which the user will get a little fine nice like a drop down and in this drop down then you can place various items like log out settings blah blah blah so imagine we have a drop down by pressing that button and upon pressing the log out button then we're going to display a dialect to the user saying are you sure you want to log out from the application so this works very nicely i mean when before i say this works very nicely maybe i should explain that by pressing each one of these items in the pop-up menu that we're going to display to the user we are going to get a call back from the system saying oh this item got pressed and you need to tell the system what this item is you can either give it like an integer like a numerical value or a string or even better better you can give it an enumeration value if you remember from the chapters where we talked about dart basics we talked about enumerations and why they're important and and that they make things very easy because when you specifying your enumeration and put cases in your animation and then you you let me actually change this to also do not do so sorry about i just remember that and you give those innovation values to your pop-up menu items by press but by the user pressing on any of those items you will then get that enumeration value back so you can do a switch statement in your a callback and say oh which item got called was it this case of the enumeration so instead of you doing like integer comparisons or string comparisons you can actually use enumerations which make your life a lot easier so we are going to talk about that soon as you can see an enumeration that describes our pop-up and we're going to work on that soon okay we talked about that um all right so now let's talk about pop-up menu button versus pop-up menu item and as you can see the caption says they're usually used together and let's go actually bring up safari here and i'm going to say pop-up menu item flutter and i'm going to bring up the document documentation up here okay so we can have a look at it together as you can see it says an item in a material design pop-up menu so this is the actual menu item itself so if you imagine we're displaying a drop down menu every item in that pop-up menu item is of type sorry every item in the pop-up menu is of type pop-up menu item all right and you can see a pop-up menu item in itself has a i mean a pop-up menu item is a generic in advanced um a dart chapter we also talked about generics and what a generic item in this case a pop-up menu item basically is is that it has a value of this type that it says is off in this case a pop-up menu item is why farther is a pop-up menu item is of type y farther now we don't really know why if either why farther is but it could just be an enumeration okay and you can see here now after you've decided decided that a pop-up menu item carries a value of of this type then its value should actually be specified and i can see that there is a case called harder in that animation that you've assigned to your pop-up menu item okay now what is a pop-up menu button so let's search here pop-up menu button okay let's go into the documentation here and you can see it says displays a menu when pressed and calls unselected when the menu is dismissed all right so um what you need to know is that the pop-up menu button is the actual button that we will place on kind of on our app bar upon pres upon pressing which it will display a menu and you can see here in the code you see here the pop-up menu button has an unselected callback and it has an item builder and items inside the pop-up menu item then are sorry the items inside the pop-up menu button are of type pop-up menu item so imagine then you have the pop-up menu button as like the parent and then you will have its item builder and each of which of these items are of type pop-up menu item and that's exactly what we're actually gonna do in this chapter okay i'm gonna close that window i don't think we need the safari window here um so now i think i explained this part of the caption a little bit just now about when we talked about the pop-up menu item but you can see here i've said pop-up menu item has a value let's look at the code for pop-up menu items so maybe we could just actually right here pop-up menu item in our code and i'm going to command click on it and you can also see that a pop-up menu item has this property called value okay and as you can see a pop-up menu item as i mentioned before is a generic class that carries a value of type t and type d basically when you see t in generics it just means something that you specified so anything that's specified inside the less than and greater than size is a generic name which then gets replaced at a compile time with the type that you as a programmer specify okay so um that's the code for the pop-up menu item and you're more than welcome to drill down more into into that code to understand it better so let's then go and create uh our enumeration that we've now talked about and i'm just going to go in here right above the notes view and let's then define an enumeration called menu action and in there we're gonna have a case called log out okay so let's say enum menu action we said we're gonna call it and then we have a case called log out in there so if i do command s to hover reload then nothing happens and the dart formatter i can actually see they form our code very well for us so the next part that we need to take care of is to actually display our pop-up menu button you can see in notes app view state app bar create a pop-up menu button of type menu action so in the app bar in order for us to be able to display a little action there we need to um actually go to the app bar here and you can see there is a property called actions which is it says it's a list of widgets all right so we're gonna say we need actions there okay i'm also just going to ensure that i have everything here so i can see the code as well and my notes i can take in my notes that we've talked about things like the menu action um all right and now we're gonna create the um pop-up menu button all right so you see the action as we saw in the source code on the website that i displayed you and that i displayed to you as the documentation inside the actions of our app bar then we're going to create items of type pop-up menu button okay so let's go ahead and do that pop-up menu button all right and then you can see it has an item builder okay and and i think it's actually an item builder and also unselected so let's first actually take care of the unselected so i'm going to put unselected command space in visual studio code on a mac and control space in linux and windows in order to get this dialog get some help from visual studio code to complete this code for us you see upon selected it's going to return the value to us and we're telling darth in here that our pop-up menu button actually manages values of type menu action all right which is what we specified right here okay and you can see we're getting an error saying that the named parameter item builder is required okay and we'll provide that now so let's go and create a item builder here get help from visual studio code with the same command that i mentioned to you before and in here then we're going to create a constant of a pop-up menu item and we're going to say that this menu item actually manages values of type menu action as well okay and we're going to say according to the documentation remember every pop-up menu item has a value so a value associated with it which then in turn gets passed to this unselected function when this pop-up menu item is tapped okay so then we're going to say in this case it has the value of menu actions when you actually log out and this child is just going to be a text that says log out okay and as a const as well actually the entire thing is a cons so we don't have to do that okay so we just uh let me have a look item builder menu actions constant body might return normally okay okay i see because the item builder if we move our mouse over it if i move the mouse over item blue you can actually see that it needs a list of pop-up menu entry and you can see pop-up menu item if you go to this code is actually of type pop-up menu entry so the problem we're seeing here is that it says you aren't returning a list but you're just returning an item so we're going to say return a list and in here we just say turn that item okay like that can we actually make that entire list const so yeah that works as well okay i'm gonna do command s and what you'll see here now is uh we've actually added log out um so and you'll see here now by pressing this then we'll get a beautiful pop-up menu here and there is a log out item in it all right so that logout text there is the child of our pop-up menu item so don't worry i mean don't get confused with the child and the value what you need to know is that the child is what the user sees and the value is what you as a programmer see because when the user then taps on that item your unselected is going to get called and then we'll get that value so just to test that let's go back to our print statement and say value and i'm going to bring up the console here going to clear it and i'm gonna change the ui layout a little bit so you see it better i'm gonna do command s and then i'm gonna tap on this log out button poof you'll see now our unselected got called and the out value which was what you associated with your pop-up menu item got printed here and got sent sent to the unselected okay so we've done that part we've handled it with double quotes we haven't really handled but we're just printing its value right now okay so i'm just gonna go through some of the things that i plan to talk to you about um uh okay all right so we can see that the print statement is um doing its job so in the previous part of this chapter i talked about why print usually isn't a good idea and there is a better way of doing print and that is with logging so dart itself comes pre-packed with a package called developer and you can easily import developer and inside the developer tools for dart there is a good function called log and you can use log which is a more trustworthy and more even configurable version of print and i'm going to show you how to do that so in your import statements let me increase the size of the screen a little bit so you see it better say import dart from dart import developer okay now i haven't talked so much about import statements before but import is actually configurable as well so in here for instance if you look at the code inside import this dart developer there's a lot of stuff that you might not need in your application okay so by importing um a package or a library in your program you're pretty much importing everything that that package also imports so in this case extension profile or service timeline and these things then get these things will then be available in your workspace just by you pressing for instance for me is control space on my macintosh so all these symbols will then be available right here so there's tons and tons of things that are available right now in your application without you having to do anything just because you imported quite a lot of things now by importing the dart developer package in this case also you're making all those symbols available kind of like globally inside this file at least and some developers don't like that some developers kind of like to limit the amount of symbols available and only have the symbols available that they actually work with okay and because of this there is a good functionality for import and dart where you can say show and by doing a show you are telling dart that um you only want to import a specific part of this package so the specific part that you're interested in is a function called log now after doing this you can basically go to your application and then say log now a lot of developers also don't like this because they think oh log where did that come from so um if you want to be more specific where functions come from especially if they're not your own functions or maybe even if you have few log functions maybe you even have a log function in in this code right here like if you say void log um like this and then you type log here i mean it's there are so many logs available now i don't even know which one is which so what dart allows you to do is to give an alias to your import so for instance if you want to use the log function that is provided in this developer package for you you can actually give an alias to this entire package in this source file which is the main dart file so you can say as i'm going to say dev tools okay so what happens here is that the log function now is not available as it was before except you have to say devtools log and then you'll see that there's a log function and that's the only function available inside devtools now because it says show if you hadn't done the show here then devtools will have everything that dev tools or the developer package in this case uh allowed you to or import it into your workspace okay so do the code then as this import devtools show log and the reason i'm explaining all of these is because i think these are so important to understand and that you need to get them like as soon as possible and now that i'm explaining these things in such detail i'm not going to explain them anywhere else in inside this chapter so i don't want to have like half explained things that we actually need to fully understand and explain half of it now and then half of it later because then you may not be able to chain the information to get the entire picture so that's why i'm explaining things sometimes in such great detail okay now that we've done as devtools show log let's go to this print statement that we put here in our notes in the unselected and then say dev tools log okay and you can see now that it's complaining to us because it says the devtools log it doesn't allow us to print a value and if you have a look at the log fi and log function signature it expects a message of type string but our a menu action is an enumeration but you can always say to string on an enumeration value in order to make it a string so um so what we're going to do then is to go and click on this log out and now you see a log item being printed to the screen and it's a little bit more distinct as well you can see now now that we're not using print using log make sure that your log items are a little bit more distinguished inside the debug console so that's also a good plus all right let's go now to the next item so what we're gonna do here now we have the log out button here so i'm going to tap on it it says log out we have that already present what we need to do now is upon pressing this item we are going to display a little dialogue to the user now if you're a designer you may be familiar with a dialogue and the dialogue is basically like an alert displayed on the screen depending on what type of operating system you're running on but both android and ios and ipad os mac os windows everything they have their own way of handling dialogues and dialogues are usually like a small little window displayed usually in the center of the main screen where that application is placed and the dialogues are configurable usually with a title with the description text or even images and usually with some action buttons which are called cta or call to action so that is the exact same case here in flutter so upon pressing this log out button we're going to display a dialogue to the user saying oh you want we see that you want to log out are you sure you want to log out and then like a cancel or no button and a yes button which is the call to action or cta okay so um what we need to do now is to create that function a function that can display an alert dialog to the user and you can see here that in the caption i've mentioned write a login function to display a dialog and its signature is kind of like it returns a feature of boolean and if you think i mean if you really think about it a dialogue that asks the user to log out either has a cancel or a null button or sorry it has either a cancel or no button and a a call to action which does the log out so it either logs out or it doesn't or basically it either confirms that you need to be logged out or it says no you shouldn't be like that so it's true false okay so a boolean so boolean is perfect for this case um and what we're going to do now is to write a function that returns a future of that boolean saying true you have to be logged out or false not and we're going to call it show logout dialog okay so let's go at the bottom of this file and and say future and bull and as i've mentioned in the caching we're going to call the show log out dialog and we say build context because we need actually context to display our log out button on okay a lot of information now um i'm gonna go actually a little bit back to the previous caption uh because i forgot to mention something there um and the important thing to mention here are two things called show dialogue and alert dialogue now show dialog actually let's go to alert dialog first alert dialog we can see is a class is a stateless widget which defines the the dialog that gets displayed to the user itself so it doesn't have any concept of being displayed to the screen or what happens when the dialogue is created after that point it doesn't care about that so it just performs the action of creating an alert dialogue for you that's for alert dialogue but you need a way to display that alert dialogue to the user and the way to do that is with show i believe it's called show dialogue and you can see here show dialog is a function that returns an optional future or sorry a future of an optional value there's a difference between an optional future and a future of an optional value so in this case it's a future that always gets returned but it optionally contains a value okay and you can see it says okay give me a context and then you have to provide a builder to me okay and this builder should return a widget so what we're gonna say is going to say show the dialogue you can see here and and and builder we're going to get help from visual studio code to complete it all right and in here in our builder what we're going to do is we're going to actually create our alert dialog okay so uh let's go back to this caption so we know what we're doing what what the actual goal is here okay so in the builder you're responsibility is to create an alert dialogue so let's say we return an alert dialog which is a widget as you saw before and it has a title you can see the title is a widget actually right like here is a widget for the title we're going to create a const of text and the text i can see we set sign out here so we're basically configuring the alert dialog okay right now the title then for the contents or the content also is a widget and we're going to say this is also a const text and we're going to ask the user are you sure you want to sign out okay just like that now that we've put the title and the content in there we need to specify the parameters call actions and you can see the type of this actions is list of widgets all right and this is like the buttons that the user will see on this alert dialog what we're going to do is going to create two text buttons so i'm going to say text button all right and don't worry about all these errors and things that we're seeing here this is because as i mentioned in one of the previous chapters or one of the first introduction chapters i think is because we have an extension here called error lens and aero lens is extend expanding all these errors that are happening as we type and it's displaying it on the screen it looks really scary it looks like we're doing everything wrong but these these bro these errors actually do make sense if you look at it it says text button the named parameter on press is required but there's no corresponding blah blah so we need to fix these things okay so let's go to text button and say unpressed get help from visual studio go to complete it and then after that i'm pressing say child so this first button is actually gonna be our cancel button okay so that's the first text button and copy this text button now and paste it in here and instead of cancel this time say log out all right and like that now you see there's a lot less information displayed on the screen and it looks a lot better okay so now we have an alert with two buttons cancel log out but you can see upon pressing those buttons we aren't doing anything here okay and we need to fix this actually so let's go ahead and first say we are returning this show dialog which returns the value of boolean and now you see we get a general error here saying that wait you said you're returning a future of bull but this show dialogue of bull is going to return an optional so what what do you mean so this is dark getting a little bit confused quite correctly actually is saying that you saying that you return a boolean but we know that show a dialogue returns an optional boolean so what do you want to do about it and a way to fix this to be honest with you is you append something called a then function to the entire show dialogue saying that okay if this show dialogue isn't able to return a boolean then i'm going to return false otherwise return the value of the show dialogue so um because i mean you may be now asking why wouldn't the show dialogue return a value it either has a cancel or a logout button but remember on android for instance you have these physical keys i'm going to change the layout so you see this button down here if i show a dialogue on the screen android users can always press this little button which will then change to an arrow down that they can press on it to dismiss the dialogue so they they have the ability to dismiss a dialogue without actually answering a question that the dialogue asks them and ios users can sometimes also tap outside a dialogue in order to cancel that dialogue so that is why show dialogue says i may not be able to return the value that i promised kind of to return should this or tap on any of my buttons quite correctly okay so append a then statement let me change the screen layout here so append event statement here which is a function that gets called should this future complete so if the user dismisses this dialogue this future is going to complete but it won't have a value you see it is an optional bull in that case so in here we say either you return a value if it's present or you return false that's it okay now you see dart is quite happy about this all right now what we need to also do is you see the way we're gonna the way we're gonna display this dialogue is to tell flutter that hey this like pause everything you're doing and display this dialogue modelly on the screen and this dialog is going to grab focus from everything else that's on the screen so the user kind of has to go and choose an item unless they want to cancel that item by for instance pressing the physical key on an android phone now when we display the dialog we're going to use the build contents context and the navigator and display the screen just like we display like a named route so the show dialogue function here inside our text buttons on press it is our responsibility as the alert dialogue to to dismiss ourselves and it's our responsibility to actually pass a value to this show dialogue and say hey this button was pressed and this is the value that it returned so what you to do on these unpressed is to say navigator of context and then you'll say pop and then you provide your value the boolean value in this case so upon cancelling we'll pop with the value of false and we copy this code and we go into the on press of the second text button which is log out and in this case we should we say that you should basically return true all right that was a lot of code i understand that let's just make sure formatting is correct as well put commas here before your parentheses end so the formatting is a little bit nicer in that case so that's our show log out dialog function now as the caption says what we need to do is to go and display this dialogue to the user and the way to do that is upon the user tapping this log out button here you see the value is a menu action so what we're going to do is going to um do a switch statement so we say switch value and what i really like about uh the this warning that we're getting here saying the missing cause clause for log out dart is already understanding that um there's a case statement and there's a case in this menu action enumeration that we're not handling and it's asking us to do that so you could tap on this little here icon and say add missing case clauses or you can say command dot on mac or control dot on linux and windows to bring up this menu also and i've also understood from my conversations with others on linkedin that this option is also available on vim and other editors because this is part of the language front end actually so it's not only a thing you can do in visual studio code thankfully so go and add the missing case clauses and in this case what we need to do now is to display our alert so we're going to say await should log out or something and we say sorry final should log out is equal to wait and now we're going to call this function that we created show logout dialog okay and now it's complaining saying that you can't do wait because this function here is unselected is not asynchronous so now we're gonna make it asynchronous and then we're gonna say devtools log should log out to a string okay so command s and let's go to our ui now and i'm going because we're doing devtools log i'm going to bring up the debug console here clear it so you see better and i'm going to press the log out now you see our dialogue is displayed to the user saying sign up are you sure you want to sign up with our buttons pressing the cancel button where we're then going to come to the unselected here and get the value of false boof you see right there pressing the same button again saying log out and then log out here we're going to get the value of true wow that was also a lot of information so i'm just going to go to my notes and ensure that i've explained everything that i want to explain all right and that was done now now that we've displayed amnata we can actually display a dialog to the user get the true and false values back we need to also ensure that we're actually logging out from firebase as well so the true or false isn't enough we need to log out from firebase and the way to do that as you can see in the code here in the captions is firebase auth instance sign out okay so um what we need to do then is to call a function so we say in here um let me bring up my notes so we say if should log out then we are going to do that because you see this should log out says true if you do have to log out and false if you don't have to so we just made sure that it's true okay so you can either say it should log out or you can say if it shouldn't log out then return and then you do the actual log out after this so it completely depends on your style i'm just gonna do if should log out because it makes more like grammatical sense for me if i should log out and do this then saying if i shouldn't log out don't do this it's a little bit of a preference but you're free to to choose your own style as you go on so let's say firebase off um instance as we can see here and then we say sign out and you can see that it returns a future avoid so let's call it and then we say wait oof all right and now that we've done that uh after we sign the user out then there's no point keeping the user in this user interface because this user interface is only for people who are logged into the application and signing out from firebase means that well you're not logged out anymore okay or you're not signed in anymore sorry you're not logged in anymore signed in anymore they could be used interchangeably sign in or log in and log out and sign up depends of the lingo that you prefer to use in your in your project i also use these terms interchangeably so if i say sometimes sign out or log out you know what i mean all right in this case after you sign up we also want to send you to the login screen because that's like the in in my opinion at least it's the most common thing to do if you sign out of an application you then go back to the login screen okay otherwise if you for instance are developing a website and then there is like a a forum website or something and the user goes and logs out you may send them them to not to the login page but but you may actually send them to like a read-only copy of all the forms available in your in your website but since we don't have any content to display to a user who has signed out the only thing we can display to them is the login screen because we don't have any other content to display okay so upon signing out we're gonna send you to the login screen so let's do that now so we're gonna see navigator as you can see in the caption of um of our context and we're saying push remove push name and remove until and then we're going to say login leave like that and we don't need the route and just like that command s all right does this make sense so let's then see if this works um so let's have a look at that uh let me also go to my notes to ensure that i'm explaining everything yep great and let's just make sure that sign out is working okay so log out we say no just to test that that is working and then log out and then we say log out here and i can see i'm even using the language like interchangeably here which is not a good idea are you sure you want to sign out and then a log out button it's not perfect but it works you're free to change this if you want to and then if you say log out then we should go back to the login screen perfect that is working but something isn't working quite right and i'll tell you soon but before we do that let's go to the terminal and go to here i have two terminals one for scr cpy and the other terminal is for doing commits messages i'm going to bring up actually so you see it better so what we need to do as we've done in the previous chapter is now that we have git and github set up let's commit our work and we're going to call this step three okay so that's what we're going to do now we are going to commit our work and we're also going to tag it so let's say git status just to have a look at what we've changed i can see that there's only changes in the main dark file and you can also say git if so you can see what you've changed you see all the green ones are new and all the red ones are things that you've basically removed or replaced with new content for instance this one was removed this one was removed and this one was added all right so quite a bit of information here let's say it gets at all so we add all those to the staging environment in order to commit them and then i'm going to say git commit with a message of step three and let's have a look at our logs i can see initial commit which is step one and then step two and then step three and then you will push these changes or push the commits to github all right now i'm gonna clear that terminal here and we also need to tag our code remember commits are not the same thing as tags so i'm going to say git tag step 3 and put your tags as well so that pushed the tags as well great wow that was a lot of work um but uh i have to kind of say congratulations for you to keep up with me in this chapter as we went through all these different bits and pieces that we had to put in place for the log out to work but like at such an integral part of our application that i think it's worth spending some time explaining how things are working also talk about a little bit of like basics of the show dialogue and menu items pop-ups etc etc so once we talk about them now we don't have to talk more about them later remember i told you something isn't quite working right here and that's what we're going to fix in the next chapter which is fixing the login screen and i'll tell you what is isn't working if you now go in here and put your email address and put your password in you can see pressing login doesn't do anything it just logs into the application because if you go to login view and we have a look at the code that we wrote here let me get rid of the console here if you look at the button that was pressed upon pressing it all we're doing is just we're doing a print user credential and you can see that if you go here oh i can see i actually got wrong password so let me go and say foo barbaz oh now we got the user credential here you see but still nothing worked even if you provide the correct user credentials then it's not working as it should and by that i mean it's not taking you to the next step what should happen in the next step all right so that is what we're gonna fix in the next chapter we're gonna work on fixing the login view so for this chapter all you all you and i did is to uh take care of our main user interface we got rid of that ugly uh done text widget that we were displaying at the end of the previous chapter and we have now a main ui with a menu bar item on top right and pressing that displays a pop-up menu which has an enum item in it upon pressing which then you get a dialog and then if you cancel um you go back to the main ui and if you say log out or sign out you go back to the long view so there was a lot of work that we did and congratulations for you for keeping up so uh get ready then and whatever you want to do get some refreshments and that we will fix our login screen in the next chapter hello and welcome to chapter 19 of the swata course in the previous chapter we worked on log out and after we completed log out you saw that we went to the login screen and um that it wasn't really working as it should in that what it was doing is um that it was logging you in with firebase and it was printing the user credentials to the debug console or the cons basically the console and we were seeing the logs but the login view wasn't actually going to the notes view so as you can see here it says the login doesn't route properly it just stays there and that's does nothing upon successful login and that's exactly what we're going to address in this chapter this chapter is going to be quite a short one because all we're basically doing is just doing some cleanup and we're going to go from the login screen to um the login view to the note c and we're going to remove some um law print statements um and this is like what what is gonna happen as you become more and more of a software developer and that sometimes you do the heavy lifting as we did in the previous chapter we took care of uh logout and you learned a lot about new classes like the buttons and the menus and unpressed of those menu items and then after you've done that you'll probably spend some time to clean up the code and this is one of those chapters that we're going to do a cleanup so let's have a look at the first thing that we need to remedy and that is our print statements um let's have a look at the code i'm going to bring up our code so i think we call it my nodes so here i think is the right window and i'm going to get rid of the debug console right there and i'm going to bring up scrcpy which i have somewhere around here okay so you can see in login view we have quite a lot of print statements at the moment they just say print user not found wrong password user credentials and etc and we also have a register view here which has a few print statements so let's go and remedy this and use log as we talked about it before so let's say i'm going to change the um view layout here so you see the code a little bit better let's go and use log and if you don't know the difference between log and print nice drawing i strongly suggest that you watch the previous chapters where we talked about this and why it is actually advised to use log instead of print and login itself isn't perfect it has it's not like problems but not problems maybe downsize or things that you need to be aware of and i highly suggest that you read the documentations for log as well but um in this case as you can see it's also suggested by the analyzer not to use a print so we're going to change that to both in the login view and registry we're going to change that to using log so let's go ahead and say import dart developer and as devtools show log all right now i'm gonna copy paste this in here as well and at the same time i'm gonna clean up the code a little bit in register view all right okay we've done the import in login view and register you want to save those and now let's go to the login view and remove all these print statements and instead just say devtools log and we're just going to say user credential to string okay remember print can print an object if you look at the information for print here excuse me you can see the function signatures is that i can print an optional object which is kind of peculiar that it can print an optional object i mean um does it mean that i don't have to actually pass a parameter no it has a positional argument but that argument can be not so i could say string um value is null like this like an optional and just pass that here so i animal still work that's what it means so let's have fun it can accept an optional object and remember every object has a function called to string so this two string functions actually coming from objects so we can command click on it and you'll see that uh let's see oh that this is the two string of user credential but if we look at um if we create for instance how do i explain the tostring and where it comes from um let's let's do it like this let's say we have an object optional object value and that is null now i can say value to string you see there's a function there so these are the op these are the functions and properties that any object exposes and every class in dart is implicitly a subclass of object including user credential meaning that user credential has inherited the tostring function from the object class however if you looked at the source code for this particular two string you can see it comes from package firebase off firebase off the dart meaning that user credential this class has overwritten the functionality of tostring meaning that it is returning its own string to represent itself all right and that's this long string that we saw actually we can't see it now but let me see if i can log in here so you see it poof and you see this user credential that is printed right here let me change the screen layout a little bit so this user credential so this is being printed or this is being returned and calculated by the to string function on user credential and you can see it looks like this user credential and then additional information and then prints the additional information and that's exactly what you can see here you see additional user info and then there's credential which i believe it should be somewhere around here is anonymous is here credential that's the key and then another one called user and where could that be it's somewhere in here i can't see it really but it should be somewhere in here user password i mean to be honest if you copied this like if i actually copied this and brought it into its own file and search for user boom boom let's see it's a little bit strange that it's all in one line but that's okay too i'm going to search for user boom and that is the user information you can see user is user display name etc so that's two string okay the reason i'm explaining all of this is because you need to know that print can print an object but log can't log needs a string so if you look at the function signature it says give me a message of type string okay so um that's what we're doing here we're saying devtools log and then user credentials to string we need to do the tostring okay so go ahead copy this dev tools log and then let's change all these print statements to say that that's what needs to be printed now or logged change all of those in your login view so that you don't have any more warnings here related to print okay save your login view and then go to register view and do the exact same thing so user credentials needs to be to stream and for weak password do the same thing email to the same thing and then invalid email entered and we have no other print statements and what you could do i mean i haven't had a plan for this uh in in my notes here i don't see anywhere that i'd plan for that but i think we could just uh we could just improvise a little bit and what i really like to do when i'm doing like cleanups like this in my source code i like to go and make sure that there's no print statement statement anywhere else because it just feels like when you're clean on cleaning up your code especially if you're doing something as simple as what we're doing here it is worth spending maybe just a few more seconds and making sure that you're applying the same cleanup in the entire source now sometimes your source code may be so big and complicated that you changing even a simple bit of code may affect the source code in such a way that you may not know if you're breaking it or anything so and for that we need tests unit tests widget tests etc but if that is the case you don't have to do that but in this case since our application is so new we've just created it there's not much logic in it i think it's worth maybe just doing a command shift f in visual studio on mac or ctrl shift f it was just here to go on linux and windows just to go go to this global search and just search for print and i can see here that we don't have any print left in our source code so we don't have to change anything else all the prints seem to have been in the login view and in the register view so don't worry about that anymore okay all right that was for our prints um so now what we need to do is to ensure that yeah basically we need to now focus on what we wanted to do in this chapter that was a side kind of like a side note there to clean up our print statements what we need to do in this chapter to make sure that we can go from the login view to the notes view i believe is what we created in the and one of the previous chapters um is it here in the main dart perhaps let's see notes view yeah so let's do that and you remember from the previous chapters where we oh we don't need the devtools log here okay if you remember from one of the previous chapters where we talked about named routes and named routes as you can see that are defined in the main function now remember the main function does not get recompiled when you do a hot reload keep that in mind so we're now going to modify our routes and allow and create a new route as you can see here it's called nodes actually it should be node slash so i'm going to hide this caption and change it so that it is actually accurate like that um and i'm going to bring it up again so you see the correct route that we have to create okay so let's go in here and create a new route for our notes and anybody who then that tries to push this route on the screen will get the notes view appear on their screen okay so let's just say as a string and notes slash as the captions suggest and then you have to provide remember the routes was a map where the keys were strings and the values had to be functions that accept the build context and return a widget it's a little bit of a string syntax but you'll get used to so the value should accept the build context as you can see here and it should return a widget so in this case we return the notes view okay as a constant okay that part is done now so what we need to do now is to ensure that upon pressing the login view sorry upon press upon pressing the login button that we are doing a code similar to what we did in um if you look here in our login view when we went to register do you remember this navigator of context push name and remove until okay so we need to we need to do that and when we do this when we did this initially when we worked with push name and remove until i don't think i actually explained entirely what push named and remove until does to be honest so i'll do that now as its name suggests it pushes around on the screen so it says that you have a screen and you want to put something on top of it okay so pushing is something that is very popular in mobile development because a mobile screen usually i mean after ios came um it became very popular that you had a screen you press the button and another screen got pushed on top of that screen so this has been available i mean in many other places even web browsers are not doing it these days and even nokia phones in in the good old days were doing the same thing but it wasn't as popular back then and it wasn't like coined as a term of pushing until ios and android became more and more popular back in 2007 so pushing is the concept of having a screen and then moving and pushing physically another screen on top of it okay so that's what push means in push name all right the named part of this function means that you have a named route so you have defined a route somewhere such as your main screen here and you are trying to push that using its name so you're not just pushing a new widget out of nowhere okay so that's what the name means now the part that says and remove until what it says is um if you have for instance one screen here another one is pushed on top of it and now you want to push another one on the screen what the remove until says it says if you want to push this one on the screen i'm going to give you the chance to get rid of the existing screen on the stack so i remove these first and then i'll push yours and this is kind of useful for for instance if you're let's say you have a login view and then you press the login button and in the in our case when the user credentials are correct if we then um if we then want to go to the notes view we don't have to keep this logging view on the screen so if this login view is here what we could do is to push the notes via on top of it some nodes view is always sitting here but then you as a programmer not the user as a programmer you'll always know that the login view is sitting behind this so that's not so good because once you're logged in and you're on the notes view you don't need this view anymore you don't need the login view sitting there and consuming memory so that's what remove until does because it gives you the opportunity it passes you see a route of dynamic and it says let me know when you want me to stop move removing things from the screen before i push yours and us returning false basically says just remove everything don't care about the routes that are on the screen at the moment and don't care about the routes that you're telling me about just remove everything and go to this register view okay all right that was a lot of information hopefully you got that so now we need to do is to go to our login view which we are right now and upon getting our user credentials here what we need to do is to send the user to the um main ui so i'm just gonna check in my notes that i've explained everything to you before we go forward and yeah that seems to be the case so um let's then go ahead and do that right here what we're going to do is going to get rid of this dev tools log here okay let's then go in here and say and navigator of and remember we have a build context and we're going to say push name and remove until uh like this and our new route name is actually what's it called notes i think we call it right in here yeah slash note slash so put put that in there and in here you could just say return false okay now this is one thing of also i haven't mentioned in the previous chapters but in dart it is very important that you always suffix your parameters parameter values with a a comma and a comma you can see here is placed usually between parameters but also the last parameter is suggested to have a comma because as you can see here the dart formatter right now isn't really able to break this these two parameters into two separate lines of code and that's what we usually do in dart you can see here for instance when we did a wait on firebase instance sign in in the last parameter we had a comma if i remove that the code will actually be a little bit uglier in this it looks like this but if you put a comma at the end of your last parameter dark is able to break your parameters each parameter and its value in its own line and that's like a usual convention in dart so if you see something like this that doesn't look quite right put a comma at the end of the last parameter and press command s for dark formatter to be able to format your uh code okay great we've done that now and at the moment we're not using the user credentials um at all so what we could do to be honest with you is to get rid of that so all we'll do is we say firebase instance sign in with email and password okay and um that's it because this whole thing is in a try block so if this thing doesn't work properly then we'll come here okay now well this is great actually now we're gonna go from our um login view to the notes view but you'll be a bit disappointed to see that this isn't going to work as it should so let me change the uh ui a little bit here and then press the login button and you'll see we get an error here that says unfortunately on unknown route was not set it's quite cute that they say unfortunately in the uh in the actual airlocks so that's what this caption also tells you you see i i talked about it a little bit before when we kind of started with this chapter that we said that we're going to put the login as our the notes name route in the main function but this is i told you that this isn't going to really work so well the reason is again the main function isn't going to rebuild when you do hot reload so in order for your changes in the main function to take effect you need to do a hot restart so what is happening here is that you've defined everything correctly everything is done right there's nothing wrong in the code itself it's just the way we are executing the code that is wrong and now you have to do a hot restart for flutter to be able to pick up your changes in the main function as well okay so hot reload is not going to do it so you need to do a hot restart so i'm going to do hot restart here we come here and now you see we're in the hello world because we are actually logged in from the previous section um i'm going to log out and we come here now i'm going to enter my details foo bar baths and please don't use football bats as your password i'm just doing it for the sake of simplicity and now we say login and you see that by doing login we come to the main ui of the application so and as you saw pushing in android using material design isn't the same thing as pushing on ios let me let me demonstrate it one more time for you so you'll have a good look at it in the login view enter your information uh through barbados and then do log in and before you do that just have just make sure that you're focusing very well on the screen i'm going to bring it up a little bit more so you'll see better um look how this main ui of the application won't actually be pushed but it instead will be kind of like moved from the bottom of the screen to the top while that previous screen gets faded away so focus on the screen please did you see that so ios and android are going to work differently differently but the concept is the same so now that the main ui is pushed to the screen where an android is displayed on the screen the login view has disappeared and been removed from the view stack okay so that's great that's all we have to do in this chapter so i hope actually you are happy with the results and that we didn't have to do too much now what we need to do also we need to make sure that we do like we did in the other chapters so let's go ahead and let's go and commit and tag our changes all right so we if you look at our tag um if you say git tag we have now step one two three and this chapter in this chapter we're gonna commit our message commit our changes and tag it with the tag name of step four so if you look at git log we did step three in the previous chapter now we're gonna do step four so let's say git add all and you can see it was just a few files that we changed now let's um i'm not sorry i'm going to change the screen layout i'm also going to say git commit um step 4 okay and um now let's tag it as well let's push our changes to uh github and also let's get a push our tags like this so if you say git tag now now we have four tags and if we do its log you'll see we have step two three and four and the initial commit which is step one all right well done that was great and work for this chapter quite a short chapter and sweet um and now we need to get ready for the next chapter as you can see in the caption here says we need to clean up our routes since they are everywhere and that means that you can see here we've defined our routes login register nodes but also in the login view we're like redefining we're saying that actually not redefining we're trying to like go to the notes route but we're typing the entire route name again and this is usually in programming not a good idea like if you have strings flying all over the all over the place like one is defined in the main dart the other one is called in the login view and this something similar is used for instance in the register view as you can see here usually this means that you need to um bring these into one central place and kind of reuse them and that is exactly what we're gonna do in the next chapter so um let's just leave it like this and i'll see you in the next chapter hello and welcome to chapter 20 of this flutter course in this chapter which is going to be a very short one i think it's going to be the shortest chapter of all the chapters we've done so far we're going to do some cleanup now you can see that uh i mean i'll show you what state we left our code in in the previous chapter this is what we've done so i'm gonna bring up the project uh files up here you will see that um the state that we left our project in was if we go to our main dart we had some routes defined i'm gonna do it like this you'll see it better we had some routes defined and um and one was called a login which the register view actually uses to send the user to the login view if the user already had a if the user had already registered and we don't actually have to talk about that without showing it so let's go here let's go here in the register view so if the user ends up in the registry and they already have a username and their email and password setup then they can click on this or tap on this button that says already registered log in here and that happens in our register view here navigator of push name and then goes to the login route which is defined in main art and kind of the same thing happens in the login view here so if the user doesn't have their if the user hasn't registered for our service then they can actually tap on not register yet register here button okay and that's the register route and the third route that we have is the notes route which allows us to send the user from the login screen to the main ui of the application which we just call at the moment notes view which right now resides inside main dart and i'll just have a look at my code here and just to ensure that that is what i had intended yeah so we haven't yet refactored notes view and we haven't yet put it into its own file okay so let's talk about hard coding now if you're not a programmer like if you don't have a software development background you probably don't know what hard coding is but i'll i'll kind of give you the um i'll give you example maybe in different worlds that may also be relevant for a programmer let's say you're working in figma and you're working with a design so you have a list of items to display on the screen and you create these list designs like you have a little cell that should be displayed inside a view then you go and copy paste this in 10 different places and then you talk to the team about the design that you've created and then they say oh you'd be really great if this label was a little bit bigger then what you'd have to do is to go to every place that you've copy pasted that cell and you have to change the label a better way of doing that in figma if you're a designer would be to create a component and then create instances of that design component in various pages of your figma design so if so you need to update something then you need to just update it in one place so even if you're not coming from a design background and you're working for instance as a project this is a product owner or a project manager you may be working with some like um excel sheets and you're creating maybe um some graphs now if you create a graph from a data set you probably want to reuse that graph in other places so if someone says okay can i get like all the graphs available in the project then you don't go and create the same graph over and over again you kind of want to refer to the same sheet in your google sheets or your excel sheets so the concept is the same you don't want to repeat yourself and that's what the mistake that we've done at the moment in our source code in that we have our routes defined in one place however where every word we're gonna use these routes we're writing their names again and this is one thing that most programmers do not like when you become more of a seasoned like a senior developer then you try to avoid these things because if we now go to our main dart file and change this login to just slash login then we have to search everywhere in our project for a name route called slash login slash as it was before and change that to this new form and that's not a good idea that's hard coding and that is why developers don't like it and i suggest that you don't like it either so uh what we're gonna do in this chapter very quickly hopefully we can get done with it soon uh be done with it soon we're gonna create a new file in our project is the first file of its kind that we're creating where we're going to put our constants okay so constants as you know from where we talked about dart are values that don't change during the compile time and they don't change during the runtime either so these are our route names because they're always constant they're no one is going in there and changing them okay so let's go ahead and do that as a caption says here let's go create a fox under lib under folder called constants and then routes and as i showed you before you don't have to create the intermediate directories in this case constants before you create the route start file what you'll need to do is just right click on lib where you want to create the constants and then the lib sorry the constants folder and then um route start file just right click here say new file then say constants um if i can spell it um and then say routes part and that will create the constants folder intermediate folder for you okay so what we need now is to define as the caption says here we need to define three routes one for the login route one for register and the other one for the notes route so let's just say const login route and we just say that's equal to login slash i'm gonna copy paste this and i'm just gonna in this second one just say this is uh register route as the caption suggests and then the notes route okay and in here i'm going to say register and in here you should say also notes okay so now we've defined these three routes but what we need to do now we've defined them but this is not enough what we need to do is to actually go and use them so let's go back to our main dart file and in here instead of using login we need to use a login route right and you can see now visual studio code smart enough to understand that this is a symbol that we've defined in a file here but this symbol right now isn't available in the current context because we haven't imported that constant routes file so if i just allow visual studio code to auto import that you can see all of a sudden the symbol becomes a valid symbol in my current context and if i go up here then i should be able to see that visual studio code has imported this file for me but if you're if you're working with veeam or if you're working with android studio and you're not given the opportunity to uh to import you can always go to this symbol and just say uh command dot or control dot depending on your operating system and just say import that library and even if your editor isn't smart enough to do importing in this way you can import it yourself so you can just say um import package then the name of the application which is my notes and then you'd say constants slash routes dot darts so there you have three ways of solving the same problem i usually do auto import so i don't have to type all of that um and i'm not gonna explain this more than in the upcoming chapter so you have all the tools necessary in order to be able to fix a problem like this okay so in here i'm going to use register route and since uh route start is now imported here here then i'm not going to have a problem and i don't have to auto import anything okay and for notes i'm going to say notes route oh that's great now we've defined them in our main function however we still have a few places where we're doing routing and we're hard coding those routes so let's fix first our notes view which is the main ui of the application so if i type here pixel tab gmail.com like that and then i say um login and we're getting some oh foobar baz in here when we do log out that's where we sending the user to the login route so let's change that as well to say login route okay so that's one place uh i'm gonna then say log out here poof log out so that's fixed now the other place we have to fix is in the login view as you can see here where we press the not register yet register here button so let's go to the login view in our views in login view i'm going to get rid of the explorer there in the in this button not registered yet let's see where it is here you see we're sending the user to the register route so i'm going to send them instead to register router and you can see you should code smart enough again to do auto import so i'm going to take that option and also we have another route here which sends you to notes where you have successfully logged in so let's just say notes route okay so that's for our login view and now the other place that we have to fix is in register so go to your project explorer and then go to register view and have a look at where we're doing this login button here okay and let's then say instead of that we're just going to say login routes okay so if you now search for push name and remove until and then show the results if you click through them you shouldn't have any routes that is hard coded okay so nodes route register route and the login route so now we fix this and just remember because we now have changed the main function here and we have some routes here do you have to do hot restart in order to see your changes but if everything's working according to the plan and that we didn't like to make any wrong choices in our rat names and that we gave them the same name or anything which we haven't if everything is working like it did before then you shouldn't see any changes in here so if you enter your information like you did before and i say foobar about then i should be able to log in should be able to log out and i should be able to go to register view or the login view so it's working exactly as it did before okay all right great stuff that was a quick chapter as other chapters since now we have made some changes and we've actually made the code better and we've tested to make sure everything works fine it's time to commit our changes as you can see the previous chapter we committed our changes as step 4 and in this chapter we're gonna commit our changes as step five and we're also going to um we're also going to tag it like we did before and let me change the layout as well so you'll see the terminal a little bit better i'm gonna do it like this gonna make the terminal bigger even so you see it even better so let's go ahead and see what the status is i can see there are lots of changes as you can see here it says you've made changes you modified these existing files and now all of a sudden there's a new folder as well so what i like to do in these cases when there is a new folder i like to do bits add all because this adds all the files and folders so you can take it at all and if you say git status now you can see the new folder including its content is now added to the staging environment or the staging area okay now we've staged so now let's commit and we say we said that we are going to commit and tag as step five so let's say step five um and then get tag um step five as well get push your changes and then give push the tags as well all right so if i say you tag now we have five tags and if i say gitland we have step five four three two and then the initial commit which is pretty much step one all right so great stuff well done for going through this chapter so fast as well together with me and what we need to do now is to get ready for the next chapter and just to give you a little preview what we're going to work on is to have a look at our error handling in specifically the login view so if i make this a little bit smaller so it's more digestible you can see at the moment our error handling the reason i put quotation marks around it is that it's not so much of an error handling to be honest with you what it is doing is just says if an error of this type happens then log this message to the console a normal user sitting with their phone they don't have access to logs they're not going to see any logs so logs are very very much useless for them and what we're going to do in the next chapter is actually display meaningful information to the user using some alert views and dialogues so grab your refreshments if you want to and i'll see you in the next chapter hello and welcome to chapter 21 of this flutter course in the previous chapter as you remember we talked about cleaning up the routes that we have in our main function and we put them inside their own dart files so that they are separate from um so we're basically not hard coding hard coding them in different places of the application we talked about what hard coding also is if you're not coming from a software development background and why it is usually a good thing not to hard code your strings and spread them around in the entire code base in this chapter we are going to focus on cleaning up error handling in our login view to start with if you remember our login view at the moment actually i don't have to say if you remember because i can bring up the code so we can have a look at it together here is our code i'm going to bring up scrcpy here as well so you can see the android phone working okay so i'm going to also change a little bit the um screen layout so if you remember uh we have our login view right here probably have to move some things around here so it becomes a little bit better layout let's go to login view and we have then our um lock statements here should anything go wrong so if we could sign in with an email and a password then we were pushing the notes route onto the screen but if there was a problem with our firebase authentication and we got a firebase auth exception we are simply at the moment logging that information to the debug console and that is not good enough because should any errors happen for instance if the current user couldn't be found or that the password is incorrect uh your end user will not receive these logs because they're not running this application beside visual studio code or anything like that except your actual users are going to be running the application on a normal telephone such as an android or an ios or an ipad even or tablet so that's what we are going to do in this chapter we're going to clean up the logic for our error handling so um so before you begin with this chapter just make sure that you're inside your login view as we are right here and then ensure that your application or your user is logged out so if you're in the main interface of the application or you're inside the notes view as we call it ensure that you go to the menu and then you log out of the application also make sure that your telephone or your emulator simulator also has internet connectivity so you can actually hit firebase back end [Music] okay so as you've seen in our login view and register view we have logic that tries to handle different kinds of errors that may arise for instance in the registration view we have weak password handling and we have email already in use or an invalid email error handling and so here we have three error handling and also in login view we have two error handling and aside from these we also need to handle the case of any other exception that might arise in this try block and we don't have that at the moment you can see we're only catching firebase off exceptions so we have to have a generic catch block at the end of our try statement in the login view and another catch block which is a generic catch block at the end of the try statement on our register view three three uh auth exceptions plus and a generic exception handling here four total in register view plus two here six and a generic one here seven so we are going to handle seven types of errors that might occur during login and registration and for any one of these we are going to display an alert to the user so we're just gonna alert the user that something has happened and it needs to be taken care of okay so let's go then into um have a look at the end of your main dart file and you can see we already have a future bowl show log out dial again this is a log out this is a dialog that you can see is an alert dialog that at the moment just returns a boolean what we need is a future void as the caption shows here a function that says show error dialog and it has a context and a string to display to the user so we're just going to use it generically generically from anywhere in the application okay so for now i need you to go to your login view and at the bottom of the login view we're going to create the function signature for this so let's just say future void and as i've called it here show error dialog and we're going to get a build context called context and then we're also going to say string text okay just like this and remember you can always put a comma here to complete the um to make sure that the dart formatter actually formats your functions correctly all right so remember show error dialogue uh what it needs to do all it has to do is just to create a dialogue and then display it so to do you i mean you may think that you always start with the creation of the dialogue but in fact you need to first think about returning the result of the dialogue which is in cases of void so you do that using um show dialogue so say return show dialog and the context is available for you as a parameter to your function and also let me should i make this a bit bigger or is the size okay i think this size is actually quite enough so now that we have that let's then go and say that we want to have a builder and your builder i'm going to get help from visual studio code to complete this you see it takes the um it brings the build context in as a parameter and it expects you to return let's get the documentation on it and expect you to return a widget and the widget that we're gonna have to display in our short in our show dialog is an alert dialog so let's go create that alert dialog all right so um for the title of our alert dialog since this is as you can see from the function signature here that says show air dialog this is this dialog is explicitly going to be used and exclusively gonna be used for displaying errors to the user so something has happened and we need to handle that error okay so we are going to in this case write a specific very specific title for our alert dialogue that the user understands something bad has happened and it needs their attention so for the title we're just going to say a constant text remember the title property if you just move your mouse over you can see it's a widget it's not a string you actually can configure the title to be whatever you want so this is the beauty of flutter almost everything is a widget so you'd expect oh the title should just be a string but no you can configure the title to be exactly what you want so it can just be an icon if you wanted to so so let's in here in the text say an error occurred and then we're going to go for the content of this dialogue remember the content comes in here as the text as a string so let's wrap that inside a text widget and we just say we display the text in there okay and for the actions we're gonna go here and let's for the actions then say we're gonna create a text button remember the text button has two parameters one is its um file the other one is unpressed the text button always has to have both these parameters set all right so what do we want to do on the unpressed we're going to just create the um function signature for it and for its child we're just going to say text and let's just say okay okay um so now we have that set up and uh let's just do some formatting in there so let's think about what we need to do on the on press just remember this dialog is just going to be displayed to the user the user is just going to get the information such as we're going to display an alert saying that oh um your password is too weak or uh hey this user already exists or this email already exists or incorrect password so it's just text and then ok button so pressing the ok button the only thing is going to do is just going to dismiss the alert dialogue so only thing you need to do in here is just to say navigator of your context and then you'll just pop this ensures that your dialogue then gets dismissed now i've done some videos about this before on linkedin and twitter i've done live videos about this where we talked about a better way of displaying error dialogues because this way of displaying error dialects is a little bit limited in that then the pressing of the button dismisses the dialog however sometimes you may need to have persistent dialogue displayed on the screen even when you push new screens on top of other screens so it's a little bit strange that a dialogue is doing navigation in that it tells navigator to pop a better way of doing this is using overlays but overlays are a little bit complicated for this part of the course so we're not going to talk about overlays right now let's just say now we have a generic dialogue that can display a text with a title of an err occurred okay all right so that is in place now and now let's go to the next item that we need to handle here and that is to handle user not found so if we go to our um sorry i just need to have a look at my notes to ensure that i'm telling you everything that i i was supposed to tell you all right so in here on your login view in the case that the error is used or not found we are going to display an alert to the user using our new function okay so in if e code user not found instead of devtools log we're going to say show error dialog the context is already available for us because you see it is passed inside your build function already so you don't have to grab it from anywhere else it's available right there and for a text we're just gonna say user not found okay and close the string you can see now if i format this um code these two parameters are displayed on the same line as i mentioned in the previous chapter all you have to do for the dart formatter to be able to format this code correctly is put a comma at the end of the last parameter and just press command s and it will format it again for you so each parameter goes into its own separate line okay um in case of the so now that we've handled user not found okay so we could literally test that let me do a hot restart just to ensure every piece of code is injected into the binary that is running in the application let's go and place an email that doesn't exist so that we get the user not found and let's just enter some password and then i'm going to press the login button and you can see now we get our error displayed on the screen that says an error occurred user not found and you can press the ok button to get rid of the um the dialog and getting rid of the dialog is happening here you see pressing that button says navigator of context pop so that's what is happening there all right great stuff what we need to do now is to handle wrong password as well and this one is going to be a breeze because we've already handled user not found so what you can do is copy and paste this code that was placed here in the user not found statement and bring it here and replace this devtools log wrong password with that and instead of saying user not found what we're going to say is going to say wrong credentials okay so let me now go and try to log in you can also do that at home or wherever you're watching this course from you can enter the email address of a user who's already registered with your application so like if you're testing you may enter the email address of the person that or your own email address if that's what you're testing with but enter the wrong credentials so there we go and then press login and now you can see that message being printed to the screen wrong credentials okay all right perfect now um what we also need to do um [Music] is handle other firebase authentication exceptions and you can see here in this case we're saying if there is a firebase auth exception and if the code is used or not found or if the code is wrong password however there might also be an exception that you haven't accounted for and although these are the most known error codes that you can get there's always a possibility that there will be another error code in the future maybe not now that you will receive from firebase which you haven't accounted for in that case the code then goes in here and says oh the code is not user not found is not wrong password and it will just fall through meaning that this entire code will this entire catch block will not be able to catch the actual exception and your code will crash so it is very or you will actually get an error screen so it's very important that you think about your exception handling early on so you don't send out a code to production that doesn't have proper error handling okay so um that's what we're going to do so two things we need to do we have to handle other exceptions that might occur and also other firebase off exceptions so let's do those things so um actually we need to first do this so let's first take care of other all firebase auth exception so place an else statement in here and then in that case just display a dialog like i'm doing here and for the error we're just going to say error and then in here e dot code now you may not be familiar with this syntax from before because maybe i haven't explained this before but this is like string formatting and guardian is very elegant it's also available i mean kind of the same thing is available in almost every language that i work with swift it's available in python when you're working with django it's available in ros it's available in javascript javascript so you're basically escaping a string and injecting some actual variables inside that all right so in python for instance you would do a f which means you're formatting and you'd be like hello and you would i think you would say dollar value and then you would put your value at the end something with a percentage sign something like that and in javascript you will do back quotes like this so and in swift you will do something like this uh e code like that inside a string so this is basically a way for dark to inject an actual code inside your string and you can see in the case of firebase auth exception the e becomes then a firebase auth exception and every exception of this type has a code of type string and this is us basically injecting that string inside our own string so every code then will be prefixed with the value of error and then a double double column here and then space and the code string itself now that we've done that we also need to handle the case where the exception is not a firebase auth exception and that's the next point that we need to talk about so in here uh at the end of this on firebase auth exception block and if you're kind of like unsure where things start and then you can see that as you go to this end of this curly bracket here you can see that visual studio code has highlighted this curly bracket right there saying that this is the beginning of the code and even if that's not enough for you you can always go to visual studio codes and gutter on the left hand side and like collapse these pieces of code so you can see oh here here you can easily see them you can also i think can we not collapse this entire if no we can't collapse that entire thing but anyway so at the end of this we need to do now is just to say catch e this is a generic catch block meaning that if the exception that occurs in the try statement is not a firebase auth exception then go into this catch block and in this cache block now e you can see is an object so it's not like a normal exception anymore it's just any object because if you remember when we talked about exceptions in dart you can throw pretty much anything in dart as an exception you can even throw an enumeration value so that's why it's telling us saying that any except any other exception other than this is just an object it's not known to me i don't know what it is so it's up to you now to display that error now if you remember from before from the previous chapter objects all have a function called tostring so that's perfect then we can go here let me expand these so that they don't become a little bit cryptic like they did and paste that code to display a show error dialogue again in here also we're just going to say e to string just like that right so we we're handling wrong credentials with handling any other error that might arise and also sorry any other firebase exception of exception and any other exception in general that might arise during logging the user in all right that was a lot of information i understand and i move past this quite fast since when we talk about one thing like we've already talked about displaying dialogues i don't think it's worth your time and my time to spend too much time explaining all of these over and over again and so and that's why i move past these sometimes quite fast what we need to do now is to do some cleanup because you see now we have our login view m here sorry login view dart file here and the m in visual studio code means modified since we last committed this into git and we have that file however we also have the show error dialog that is sitting here that is also going to be useful for the register view however it's right now just sitting in the login view so if register view wants to then use this same code you will have to import the login view and then use this feature it's a little bit wrong this is supposed to be like a generic show error dialogue and it should be available for pretty much any piece of code that needs it so what we were going to do as a caption says here we're going to create a new file um and folder as i can see under lib so open your project explorer under lib go and create and you can see here we need to create a file called show error dialog dart and it's it needs to be inside a folder called utility so i'm going to right click on lib and say new file and i'm just going to type utilities slash show error dialogue dart all right and go to your login view and grab that code uh for show error dialogue uh poof i'm gonna grab the code and cut it however you cut in your operating system in mac is command x in visual studio code and bring it into your show error dialog file all right we're gonna get a lot of uh errors but as i've explained in the previous chapters we can also import these things material dart to get rid of almost actually all of those errors so that was fantastic now that we've done that you can see visual studio is already showing this tab the login view as having an error and that is because login view is using show error dialog but now that we've removed show error dialog from there it doesn't know where this show error dialog now resides so what we need to do is to use our new file in the login view dart file and you could do that you could ask visual studio code to help you with this and you could just say import library and that's it it imported it for us and as you can see now that we're we don't have any more logs inside our login view visual studio code is helping and saying you're no more using you're no longer using the dev tools or the dart developer package import what you can do is just to safely remove that and clean up your imports as well while we're going okay so um that is working fine and we can just confirm that so i'm just going to enter an existing email here with the wrong credentials and just to ensure that we're getting the dialogue wrong credentials okay perfect now that we've done that i'm going to change the screen layout a little bit and what we're going to do is that we need to wrap up this chapter we've cleaned up our error handling and we need to just make a commit remember pretty much in every chapter from a few chapters uh back onwards we're to commit our code at the end of the chapter just to make sure that you have traceability for for your code and this is what you will need to do even if you're working for instance actually especially if you're working inside a a team with other people doing flutter code or any other code you need to ensure that your code which is ready or even if it's not ready it is committed so um even if your code isn't ready you can commit it into a specific branch but you should never leave your work day without committing your work remember that okay so let's now go and commit our work i'm gonna bring up the terminal a little bit here so and you can see that the previous chapter we did a step five and in here we're going to commit our work as step 6 and also we're going to tag our work okay so let's say git status you can see utilities is a new folder i'm just going to say git add all i'm going to increase the size of the screen as well so you see it better make your studio code a little bit larger as well clean and get add dash dash all and then git status now you can see these are staged for committing and i'm going to commit them as step 6 i believe after doing that let's tag it as well as step six um and get push our changes and we're also gonna push tags all right that is absolutely perfect so that was that to be honest with you for this chapter so this was a quick chapter as well and that's completely okay actually quite refreshing to have these short chapters for me as well um so now that we've done error handling in our login view we also need to clean up our register view you can see our registry has kind of the same problem as login view had at the beginning of this chapter in that we have a lot of error like dev tools log stuff in here which aren't so useful so for the next chapter um what we need to do is to ensure that we're logged out of the application and that we can go to the register view as we can do here so that's where you need to be for the next chapter and before we can continue with that with the course to the next chapter so i hope you enjoyed this chapter and i'll see you in the next one hello everyone and welcome to chapter 22 of this flutter course in the previous chapters we've been talking quite a lot about login and register and email verification and as you saw in the previous chapter and we have some problems still in our register view in that when we come to the error handling we're still doing logs basically instead of using our new function that was called show error dialog and also our register view basically isn't really able to send us to the correct place after a successful registration you see we have email verification set up in that every user who registers also needs to verify his or her email before entering the main ui of the application so if that is the default behavior in that a newly registered user needs to verify their email perhaps it would be best that we send the user right after registration to the email verification view and these are the things that basically we're going to solve in this chapter fixing our log statements in the register view and also sending the user to the email verification view sending the registered user to the email verification view right after registration okay so these are the goals of this chapter so you know and i'm gonna bring up my visual studio code to the screen so you can also see it i'm gonna bring up scr cpy to the right hand side so you see you see that too position these windows a little bit better alright so the first task that we we need to do here is to make sure that we're using show error dialog in our register view and if you haven't watched the previous chapter that's what we did in one of the previous chapters that we talked about this uh file here in utilities show error dialog that increase the size of the window so you see it better so this show error dialog is a generic dialogue that has a title that says an error occurred and also a text of your choosing so let's go to our registry view as the caption says here i'm going to minimize the terminal here and get rid of the explorer and let's go to this weak password and then start typing show error dialog and you can see it's gonna auto import it excuse me it's going to auto import it for us so let's say show air dialog with that context and i'm just going to in this in the case of a weak password um we need to just say weak password okay so that part is done and you can also put a comma at the end of the second parameter just to make sure that it is clean but remember also that show error dialogue is a is an asynchronous function so if you move your mouse over it you'll see that it says future void so by just calling show air dial like you're not showing the error dialogue you're basically just telling the short i like to return the future which in turn then uh can display the error dialogue if you await on it so don't forget a wait after doing that let's remove our dev devtools log from there from the weak password and if statement and now what we're going to do is to copy this code that we wrote here and go to email already in use and display another error dialog in here using the same exact code and i'm just going to say email is already in use okay so that's for email rna news and also for invalid email we're going to say just invalid let me have a look for invalid email if you should just say um this is an invalid email address right and i can see that we haven't really handled other exceptions that might occur because you remember in the login view we had a look at handling for instance other uh other exceptions that might occur like firebase off exceptions that we did in an else statement there and also we did a generic catch statement that catches any other exception that is not a firebase auth exception and i can see now we haven't done that in register view so let's go and take care of that so let's just say else so in this else statement we're catching any other firebase off exception that might occur okay so i'm just going to say here and i'm just going to say error and dollar e code okay so that's very similar to what we're doing in our login view so and i apologize i could just see that you couldn't see the code because it was hidden behind the caption but now you can see it so i'm putting an else statement here and then i'm saying basically a weight shorter dialogue and e code so that's for if you if you look at have a look at this um curly bracket right here which you can now see this purple one it it starts here because it's the beginning of where we start catching firebase off exceptions and what we also need to do is put another l another catch statement here which catches any other exception that is not a firebase auth exception okay so we've covered this in the previous chapter when we talked about exception handling in the login view so i don't think i need to explain that again um okay so what we're going to do in here we're also going to show the error dialog in this case as well but for the message we're just going to say e2 string okay similar something similar we did in our login view actually exactly the same thing okay that was great so now we're using short error dialog instead of log in the register view and now basically i don't think we're using dev tools over using devtools login here i don't think we need to do that anymore so we can get rid of that and we can also then get rid of devtools um import over here okay it's gonna have a look at my notes a little bit just to ensure that i'm telling you all the information that you need to know that's great okay um now that we've done all of this we need to also make sure you can see as the cache that says after every registration we need to confirm the user's email and that is like the um the pattern of every newly registered user in application that a newly registered user cannot have already confirmed their email because it's just not possible the two don't go together a newly user a newly registered user hasn't had their email address registered in our system therefore has not received a verification email during this session so this is a pattern that we need to basically help our users with so after every successful registration we're then going to automatically send the user to the verify email view and if you remember from the previous chapters we have this verify email view right here which is its own stateful widget and i mean it doesn't necessarily have to be a stateful widget i can see it's not doing anything stateful but we've just left it that state will stay full widget and it can just be like that for now um but we can also turn it into a stateless widget if you want to um okay so that's for the pattern of what our users are doing with the register view so if we go to register here uh oops no we are actually on the register sorry about that so um okay so what we need to do now is since we're gonna send the user from the register view we're gonna send to the verify email view we need a route for that and if you remember from the previous chapters we're defining our routes now inside this file lib constants routes dot dart and we've right now defined login route register route and nodes route then we need a new route for the verify email view so let's go ahead as the caption says in here and just type that and just say cons verify email out is slash verify email like that with a slash at the end as well now that we've defined the route we need to then go excuse me we need to go into our main dart file so i'm going to close this file close this file and then command p on mac in visual studio or or control p in linux and windows and go to main.dart okay in your main.dart you remember all the routes were registered inside the routes parameter of your material application so let's go ahead and register the um email verify email wrap here and we say context and we just say const verify email view and so that's also then registered inside the main function okay remember anything that you're doing inside the main function is not going to be reloading when you do hot uh hot reload so you need to do a hot restart here in order for for those to for for those changes in the main function to take effect so i'm just going to do a hot restart here okay so let's now that we've registered that let's go to our register and now that we've registered there are so many registered words i'm throwing out there so i just want to clarify now that we've registered to verify email routes in our routes in main dart we need to go to the register view and use this verify email route in there after a successful registration okay so um let's then go to our i'm going to close this and i'm going to go to register view right here okay here i can see that we're getting the user credentials and then assigning it to this user credential we don't have to do that anymore so let's just remove that we are not going to actually use the returning user credentials upon a successful create user with email and password we're going to go to the next line automatically because we have a try and catch statement here so now what we need to do is uh we're gonna show the verify email route okay uh so let's go uh to our uh verify email around in here and what we're going to say is to say navigator and dot push navigator of context and then we're going to say push named and you see in this case we're actually going to say push name instead of using the other functionality that says push name and remove until and the reason behind this is that um when when a user is inside the registration page here and when we want to go to the let's say that you enter some email in here and then you enter some password and you click the register button or you tap the register button and we send you to the verify email page where we say oh um here you can verify your email et cetera now in there if you if you realize that oh i register with the wrong email you need to be able to go back to the register page so in order to avoid having all these buttons that go send one user from one page to the other it would make a lot more sense if he from the register view could just push the new uh email verification route so we don't replace the entire routes like the register page with the new route so basically the desired effect here is that our register page is gonna stay right here and then we're gonna push the verify email route on top of it if the user in the verify email route realizes that they've done something wrong with the email address then they can just press the back button on the top bar and go back to the register page so that it's just a natural way of navigating between screens so that's why we're using push named in this case okay so i'm gonna say push names and push name and and then in the name we're just gonna say verify email route oops and verify email route like this i'm gonna do a command s right there and um then let's make sure that we can put all of this in action all right so i'm gonna hot restart just to make sure you remember we did a change in our main function so if you forgot to do hot restart please do that now um so that your changes can actually take effect from the login view which is the first view that the user sees we're gonna go to the register page and inside this register page i'm going to register with a new user so since i've already registered my user and i can actually go to firebase console so let's go to console firebase the user which i usually use is already registered with this application so my notes flutter project okay let's go to authentication and i can see pixelityab gmail.com is already registered so i'm going to register with a new user in here i'm going to say van.mp and the password is foobarbaz i'm just going to choose here and please don't use this password in production for any of your accounts anywhere at all this is just a bad idea i'm using fubar bass for consensus consistency and and for the sake of simplicity in this project so because for me it's a lot easier as i'm typing and writing all the passwords over and over again just to use fullbarbass but this is not a good password so i think just to make this clear um now i'm going to register this user and now you can see that after a successful registration now we're ending up in this verify email screen and this is really good and but there is a way we can actually make this better and let's go to firebase here and i can see now that user is already registered here you see and it has a user id and here's the last sign-in date okay so how can we make this better you see if this is the natural flow of going like when the user is in the register page or the register view and they always end up in the verify email page the way that we can make this better is um that upon successful registration right before we push the verify email view on the screen is that we actually send a verification email to that user because otherwise what you're creating you're creating a logic for the user that they have to take an extra step in order to verify their account so they come here and now they have to press another button but it would be really good if you actually did that button press kind of for them before we went to that screen so we're not actually going to physically like tap that button for them but we're going to execute the same code that that button executes for the user okay so that's what we're gonna do now so um as the caption says in here in your register view right before you navigate to the verify email route ensure that you get the current user basically so you say final user is firebase off instance i believe and current user okay get your user and then in here you'll say user um and there is a function called send email verification and remember your user is an optional user and that's why you're seeing this elvis operator here which is kind of like a moustache or something i don't know what you want to call it some some people call it elvis operator if you're coming from kotlin or in swift you would say like an optional invocation depending on the language that you're coming from but if you're not if you don't i have like a software development background then you may just call that a question mark um remember now so user is optional and this function returns a fusion voice so you can't just call it you need to wait on it and so now we're doing that so we're now awaiting on that all right and also since now we've changed our logic in that when you press the register button upon successful registration we're sending you an email verification is not a good idea to end up on this screen that just says please verify your email address because let's let's just face it we have already sent an email verification so we don't want the user to click this button actually we want the user to click this button or tap this button if they haven't received the email in a while all right so we don't want like double emails for users so it's just not a good idea so uh sorry i'll just have a look at my notes a little bit here okay so what we need to do now is as the caption now says here we need to go to our verify email view and add a text on top to say we have already sent a verification email okay and that's just common sense okay so let's go to our verify email route which is basically verify email view in here and you can see that we have a column in here and the first text at the moment says please verify your email address so let's create another text in here i'm going to say cons text and i'm going to say weave you see because i want to write the word weave as in we have there is a single code in here so i cannot have my own string having single codes because then dart doesn't understand where this what this string is because it thinks here's a string that starts here and it ends here but what is this one so in in order to have single quotes inside your dark strings then you would have to encapsulate or basically put your string inside double quotes so you avoid that confusion so we can say we've sent you an email verification please please open it in order to verify your yeah so please open it to verify your uh accounts something like this okay and also this text then we need to change that as well because you see we don't want this text to be kind of like a call to action saying that hello like here we're saying we sent you an email verification please open the verifier again and then right after that we're saying hey click this button so that's not a good idea let's just change this text and say if you haven't and let's make this double quotes as well just the same story as before if you haven't received a verification email yet press the button below something like this okay so i'm just gonna press command s and now you can see those texts being displayed on the screen they're not very pretty to be honest with you at the moment but that's okay too so um that's not a problem let it be like that all right so we're displaying that text uh to the user and what we need to do now uh is to test this whole uh flow basically again just to make sure that yeah it's working as expected so in order to do that go to your firebase console again and i'm gonna bring up the console in here hopefully you can see it too and i'm gonna go to that project then authentication and this user i'm gonna delete this user okay delete boof all right that user is gone i'm gonna close the screen now and and what we're gonna do then is just to hot restart the application in order to clean all the states um to restart is it not taking effect all right i'm gonna then uh verify email i can see that there is no back button and it kind of feels like uh we're ending up in in that screen because in our main dart file and let's go in main dart i believe that we're actually sending the user to verify email view in this case user firebase instance card okay so this is a lot a little bit a bit of a problem because now we're kind of like stuck in this uh in this view because firebase as a caption right here says it says firebase doesn't understand the remote changes we removed that user completely but firebase still believes that that user exists and that is because you see firebase can't like the client that is inside the code that is inside the client application which you are developing can't constantly talk with firebase and say give me the latest state give me the latest state this user that is right now on this on this phone is a local user that once had a connection with the backend but it doesn't anymore but firebase doesn't like delete this user locally so so what we need to do the best way to handle this case is to have kind of like a restart uh button in our verify email so if for some reason the user like in this case understands that hey um i'm stuck i need to get out of here from verify email i kind of want to go back to where i was so what we need to do is to upon the user pressing a restart button here we want to sign that user out so firebase understands well this user isn't signed in anymore so that we don't end up in this case that email is verified etc etc and we also are going to send the user to the register view okay and as you can see we can't send the user back to the register view i mean that we can't expect the register view to exist on the view on the view stack in this case because if a user has just freshly started the application application so they will end up in this future builder the future builder would then check the user and says oh you should go to the verify email view and in this case there is no register view behind the um verify email view so in that case you will see that we won't push but we will actually do push name and remove until but we will get there soon okay first off let's go to your uh to your verify email view and right after this text button we're gonna add another text button up a little bit so you see it better and let's just say a text button unpressed is just going to be empty for now and then for his child we're going to add a const text that just says restart okay so that's that and then here what we then need to do is as i mentioned before is to uh and as the caption explains here we need to actually log the user out so let's say firebase auth instance and and then what we need to do is to say sign out okay remember cyano i also believe is a future of void so you need to await on it so oops um see i just jumped screens without actually really wanting to do that so let's wait on it and it's going to give you an error because now your unpressed function is not async so make it async right after doing that using if i do command s now we're gonna see the restart button here but doing that just does a sign out it doesn't actually send you to the register view and we're gonna take care of that soon so as a caption says navigator of context i push named remove until and in here we're going to send the user to remember from our routes view sorry a routes file there is a register route okay so let's go there let's go register out and in here we just leave the code as it is and i come at the end to clean it up a little bit and and that should be good to go okay now i'm gonna do a hot restart you'll see now we end up in here and because it's still the user is logged in because we haven't executed this code yet and i'm just gonna then press the restart button and you'll see we end up in the register view just to make sure that we're not going to go into this vicious cycle again that every time we do a hot restart we're going to end up in the verify email view and let's just do a hot restart now to see what the state of the application is going to be and as you can see upon hot restart we end up in the login view which means that the main dart file in the future builder it went to this code so the user is null at the moment and that's exactly what we wanted because we signed the current user out okay all right so we are then going to use the same credentials to um as before to register let's just go to the register view then and i'm going to say round.np np gmail.com and then fubarbas and i'm going to then register this user and you can see it says it sent you an email verification please open it to verify and i can see on my third screen here that i actually got the email um verification so as you can see in the caption it says get the confirmation email but don't confirm yet because we kind of need to have a look at a problem that we have in our application so um now let's see if we can log in so what i'm going to do is to go back on the screen from the verify email go back to the register view and instead of doing a registration again go to the login view now use your current uh like the new user that you just created but you haven't confirmed the email use the credentials of that user and say gmail.com and foobar as and then press the login button you'll see now we've ended up in the main ui of the application and that is problematic because any user just like i did can go to the register view then they will go to the confirmation view automatically they say okay i got a confirmation email and then they don't confirm the email they press the back button to go to the registry view again and from registry google they go to the login view and then they log in so because you see in our login view and here in this code right after signing with email and password we are not verifying that the user has actually verified their email address we're just saying sign in and firebase says all right sign in great the email and password match an entry in the authentication database i'm good to go and then we're just saying push to notes wrap so that is a problem um that we have that we need to fix in the next chapter okay but for now we've got a lot of code i can see all the files are changed so let's commit our code and tag it like what we're doing in other chapters as well gonna go to the terminal i'm going to change the screen layout a little bit so you see it better increase the size of the views so you see it even better and you can see the previous tag was step 6. now let's have a look at the status of our code and i can see there's lots of changes modified you can always issue the command g apa which i call gopa and that will show you all your changes but i'm just gonna say git commit sorry good at all i'm going to say git commit and we said that we're going to commit this as step 7 okay and push those changes to github and i'm going to also tag it as step 7 so like that step seven and then i'm just gonna say git push tags all right fantastic now as the caption says here we need to get ready for the next chapter and as you can see it says user needs to verify email before going to the main ui because that is as i explained there is a problem that we have which we haven't addressed yet but it's quite easy to address as you'll see in the next chapter so uh i'll see you there hello everyone and welcome to chapter 23 of this vlog course as you saw in the previous chapter we talked about cleaning up our registration flow so that when we tap on registration or the register button we actually send an email confirmation to the user and we saw that we go to the email confirmation view and before we even get there we then receive our email confirmation in our inbox so that all worked very well except for the fact that now a user who hasn't registered who hasn't verified their email account can still end up in the main ui of our application and that's what we're going to fix in this chapter so as the title shows here or as the caption shows here what we need to do is to ensure that we first before we continue with the chapter we need to make sure that we've logged out of the application so um now that you're in the main ui of the application let's just go in here and say log out and we're logging out to end up on the login screen i'm gonna i'm also gonna bring up visual studio code as we left it before so what we need to do now i'm going to close other tabs except for the login view excuse me and you can see in here right after we're signing with email and password right now we're sending the user to the notes route and we need to clean this up so what we need to do is just to get the current user from firebase and i'm gonna bring up the correct correct caption as well and i'm gonna change the screen layouts a little bit um so you see the code better so as you can see the caption says you need to add an if statement before you send the user to the main ui of the application and to make sure that the user is verified okay so in order to do that we also need to get the concurrent user so we can say final user is equal to firebase off instance firebase off instance and the current user okay so that's for the current user and we're going to say if the user optional you see we need to optionally access that email verified or false when we get a boolean value here either this returns a true or reuse false so in here we say user's email is verified otherwise user's email uh if i can spell it is not verified okay so now we have the two conditions in there so what we need to do now is to grab this code that we had from before you can see it sends the user to the main ui of the application and of course that needs to happen only if the user has basically verified their email address so grab that code and place it in user email is verified okay in here and in the case that the user email is not verified then we kind of need to do the same code but instead of going to the nodes route which is the main ui of the application we actually know we need to go to the verify email route if you remember from the previous chapters in a route start we've already defined verify email route okay so let's go back in our login view and then paste the same code except for going to notes route we're gonna go to and verify email routes okay so really all we have to do for this chapter so it's just cleaning up the logic one step at a time okay and that's okay some chapters are going to be long some chapters are going to be short it's actually quite refreshing even for me to have some shorter chapters so um now what we need to do is let's put this to test and as you can see what we're going to do is to remove that test user again from firebase console and test the entire flow again so i'm going to do a hot restart here and just to make sure that the state is completely restarted i'm gonna bring up a firebase console let's go to our application which for me is called mynotes flatware project i'm gonna go to authentication and remove that test user that i created here okay delete and do another hot restart just to make sure the cache is invalidated if there's any cache in there and what we need to do now is to just oops what we need to do now is to do kind of like the same registration again so i'm gonna go to the register page here and then i'm gonna go to your enter your email here and i'm going to write the same email address to register the user again through bar bath press the register button and we end up here then i'm going to do the same hacked as we did before uh press the back button and then go to the login screen i'm going to type the same credentials and say fubar baz if everything is worked according to our plan upon pressing the login button the code is going to end up in here saying that the user's email is not verified and it's going to remove the login route from from the stack and push the verify email route on the screen okay so both and that is exactly what we're getting here you can see we're going to the verify email view as we planned okay as i mentioned this chapter was a short one and that's actually really good so what we need to do now is to focus on what we're gonna do in the next chapter as you can see it says our authentication logic is all over the ui and we need to make a service for the authentication you see up until this point we've been working with firebase directly in the source code in that we've been like writing firebase auth code pretty much in our ui now you may think that well that's okay i mean if you're if you don't come from a software development background you may think that that is fine and it should as long as it works but the software development industry has shown us over and over again that the saying of oh if it if it's working if it's not broken don't fix it that that doesn't that doesn't really apply to all cases as we've seen uh in the case of for instance log 4j uh it was working but then there was a security flying and everybody had to go out to their code base and fix everything so we're entirely still of the weekends so the code works but there's a problem with it in that here you have your user interface so the code is quite high level it's like literally the user is here and then we have our user interface here and then we have like the code that we've written and like a little bit more low level like our if statements and then firebase is sitting all the way down here and we're like exposing this firebase layer all the way to our ui layers the ui is talking directly with a layer of the code that is so level that they shouldn't have direct connection with each other so if you're not from a software development background this may be a little bit alien to you but software developers really like to make sure things are com liking their own compartments so what we need to do is in order to get ready for the next chapter is just get a good cup of coffee or tea because the next chapter is actually going to be a long one and it's going to be a complicated one but i'm gonna do my best to explain all the concepts as good as i can but just know that the next chapter is gonna be a big one okay so uh grab your refreshments juice tea water coffee whatever you want and i'll see you in the next chapter hello and welcome to chapter 24 of this flutter course in the previous chapter we talked about ensuring that the user's email is verified before he or she can proceed with the with by before the user is able to go to the main ui of the application um and what we are going to do now is take a step back from developing our ui and logic of the application by creating an auth service so i'm going to provide you with a caption here and as you can see it says auth provider auth service meaning an author provide abstract class on an off service now if we have a look at the code that we've created so far let me bring up visual studio code so you can see it on the screen like i do here um i'm going to increase the size so you see better and i'm going to bring up the application as well so we can see it side by side i have three screens here so it's a lot it's a little bit difficult to juggle um excuse me so i'm going to change the screen layout so you see the code better if you look here we have our um three views login register and verify email view okay or we actually have four views the other one is the main ui of the application um which we have right now created in here notes view excuse me but if you have a look at the login view you can see one of the things that we're doing immediately as we go to the login view is um is not actually immediately by pressing the login button we're talking with firebase off signing in we are kind of doing the same thing talking with firebase by uh in the register view you can see firebase auth instance create user and we also have firebase in our verify email so you can see here we are actually importing firebase auth firebase so if you're not uh like if you don't have a software development background from from before you may think well this is this is fine very important firebase but you also need to know that firebase is kind of like a low-level abstraction layer that um that is talking to the firebase backend and providing you with a lot of high-level uh functionality but those high-level functionalities at the firebase level they're kind of high level but if you think about that firebase is a dependency that we're bringing into our application that's talking with firebase back-end in itself is low-level compared with our ui so if you think that the ui code is here then what we are doing is that we're like saying here is firebase and then the ui is talking directly with the firebase libraries and functionalities and in the in the eyes of a like a software developer has been doing this for a while this is not a good idea simply because we're missing a little bit of a layer in between the ui and firebase which abstracts away the firebase functionality from the ui of the application and as we talked about it before um it is possible that in the future you may want to allow for instance apple login or google login or sign in with facebook etc various options for signing in and if you look at um the console at firebase you'll see immediately that you have various ways of authenticating a user at the moment we've enabled sign in method for email and password but you also have the ability to add a new provider you can as you can see google facebook and these as you can see they're called providers a new provider and that is what we're going to do in this chapter of our flashlight course as well so we're going to take firebase and think of it as an authentication provider okay so we're going to create a class which i believe we're calling at the moment firebase auth provider but we're gonna say that this firebase auth provider comes from another class which is called auth provider so what we're gonna do then is gonna say okay any auth provider that needs to that our application can work with is expected to have certain functionalities and certain properties okay such as the current auth provider should be able to return the current user the author provider should be able to log a user in um log user out register users send an email verification so these few basic functionalities so that will be our abstract offs provider class and then we will create another class which is as we call it it will be the concrete implementation of that abstract class so think of the abstract class as kind of like a as it's it is our um contract so we're saying any authentication provider such as google facebook etc will need to conform to the functionality that we specified in this abstract class okay then we will go and develop a concrete implementation of that abstract class and we will call it firebase auth provider and we will actually place the real implementation of our authentication for firebase such as creating a user logging user in etc etc in that concrete implementation okay and then what we will do also we will create another class which we will call it i believe we call it off service and its goal and in this course it won't do so much what it will do it will just take a provider such as a firebase auth provider a google auth provider and it will just expose the functionalities of that provider to the outside world and and the goal of this is that so we will have our ui talking with that service and that service will talk to a provider which which is the firebase auth provider and that firebase auth provider will talk to firebase so we're right now we have firebase ui but after after the end of this chapter we will have firebase um firebase auth provider auth service and then the ui so we will have two layers sitting in in between and you may actually correctly think that well this is a lot of work why do we need that but for me i if i wanted this course to be just another course where i show you how to include firebase then it wouldn't be to be honest with you worth actually doing yet another course about firebase and flutter because there are lots of courses available maybe not maybe not courses that go through so much details as i am going but i still believe that my job here is not just to make you a developer but also make you a good developer where you take some extra steps in order to make your code a little bit better and this is why you will actually notice as as you get more into software development and working with others in inside teams which you may not be doing at the moment but when you get your first job a software developer you'll understand that other software developers are actually taking some extra steps in order to make their code a little bit easier and better to maintain so that's what we're gonna do in our code okay so um that was uh the intro for this chapter what we need to do is to um first think about how we're handling our um exceptions if you look inside the i mean in the verify view we're not taking care of exceptions as such maybe that's something we'll need to do as well but if you look at the login screen for instance we're having here a try block and then when it gets to firebase off exception we're handling user not found wrong password and then if anything else happens we just say show error so here there are two specific errors off errors that we're handling wrong password and the user not found and if we go to the register view you will also see we have weak password email already used and invalid email all right so these are some of the exceptions that we'll need to handle in our um in our application but right now as you can see our ui is going directly to firebase auth exception and it's like importing firebase auth exception which is created inside let's have a look firebase off accession src interface it's in um it's in one of the files which i believe is accessible through firebase auth so if you go to firebase off that probably imports all the exceptions as well there we go here it is so so our ui shouldn't really know anything about firebase off by the end of this chapter so let's take the first step here then and let's go and create our as you can see a new file under lib under folder called services auth and then off exceptions.dart so i'm gonna do that right now i'm going to collapse these and let's go under lay down you can see that we don't have con right now we have constants utilities and views so we don't have anything called services so let me right click on lib and say new file and you can do the same thing and in here just enter the entire path so say services off and then we say off exceptions.dart okay [Music] oh that is our new file that we created in there and what we need to do is to go and define all those exceptions so let's begin by saying that we need a new exception called user not found off exception and if you remember user not found is something that we're handling here do you remember firebase off exception in the login view and if we cannot find that user we're just showing an error saying show error dialog so let's define an exception for that and i'm going to say class user not found and off and i'm going to say implements exception so this is a typical way of creating exception classes in your in your application that you say and here is my own class that is that for instance represents an exception and it's it's good practice just to say that it implements an existing exception exception you can see here by command pressing on it you can see it goes to flutter bin cache core exception start so it is already imported by default you don't have to import any specific file in order to get access to the exception class so it's it suffices that you just implement that class okay so now let's go ahead and implement the next exception as the title as the caption says here wrong password off exception and that is also handled inside our login view wrong password right here so i'm just gonna go and kind of like copy that code and in here i'm just gonna say wrong password auth exception all right what else are we handling here nothing else in the login view at least so that's that's really good so i'm just going to close the login view for now and save this file okay so let's now start taking care of some of the exceptions that we're handling in our register view and let's go to register view and you'll see here that the first section exception that we're handling is called weak password so i'm going to put a comment in here and a comment in here i'm going to say login exceptions and and register exceptions okay so as the caption says let's create a class called weak password auth exception gonna copy this code from here and i'm gonna say weak password off exception so that's for the register views weak password the next one is email already in use so that's what the caption says here as well so let's go and copy this and i'm gonna say email already in use auth exception okay so now we have the password and email already and use exceptions and let's have a look and we also have the invalid email auth exception which i don't think i had planned for but let's go and implement that as well so let's say invalid email author okay okay um now what we also need to do is to define a few other exceptions as you remember from register view we also have the case of an else where we basically say something else happened here it's an off exception but something else may have happened that we haven't handled with this code or we may also have another cat statement here that catches like generic exceptions and we're we're doing the same thing as you can see the code here um and let me change the screen layout so you see it better i'm gonna go to the login view as well because we're doing the exact same thing in the login view in that upon getting a firebase auth exception this code then we also have an else statement even in there so we're saying if the code is not like handled by us it may be another code in that case also show the show error dialog or in that case show error dialogue and we're also doing a catch like a generic catch as well so we need kind of like an exception that handles all those cases so an unknown code during the firebase off exception and an unknown exception so we're gonna create a generic exception all right i'm gonna change the screen layout a little bit um like that i'm gonna go to my notes okay so let's just in here say generic exceptions um and i'm gonna bring this one up as well today i'm gonna bring this one first so let's go ahead and create a generic auth exception i'm gonna copy this code from here i'm going to say generic auth exception okay and what we also need to do is to provide this thing user not logged in off exception and you will you will know now that um i mean you will need to know why we're actually having a use or not logged in off exception and this will be an exception that our um that our firebase provider will be able to throw if the user is null after registering that user for instance so let's say that we tell our auth provider we say register a user with this email and password and no exception happens nothing so we the application thinks that all right everything went as expected but what if the user that we access at firebase auth is null in that case our auth provider should be able to handle that and send an exception saying that oh i couldn't find this user or this user isn't logged in so let's create that exception as well so i'm just going to say user not logged in exception so let's just say class implement exception okay so user not logged in off exception and i'm gonna save that as well all right that was a lot of work now we have created all those files oh sorry maybe you didn't actually see the code that i wrote i don't like having captions up all the time but i also think captions are so important so that you always know what we're working with but the downside of having these captions at the bottom left of the screen is that sometimes they hide what i'm typing so i'm doing my best really to catch those and catch that issue and if i see that happening i'll i'm gonna bring the screen up like this so you see it but sometimes i may be missing that i apologize for that so let's let's say that and now we've implemented all our exceptions and as you can see in the captions it says we need an auth user we shouldn't expose firebase's user to the ui and this to be honest with you is the same story as we had for our exceptions the ui code should not at all be working with firebase the ui code should be so high level and so abstracted from the rest of your application that it shouldn't even at all know how it is functioning you're just giving it different providers and services and it should be calling those services and providers not really knowing how they're tied together and at the moment you can see our login view it's like where let's go in here you can see here in login view and for me it's on line 67 for you maybe in a different line but we're after calling the sign in with email and password function which we also shouldn't be doing but what we're doing after that is we're getting the current user from firebase and this user is of type you can see let's go in here and see it's of type user so if i go put the type in here and command click on it you'll see this user is part of firebase auth you see there's a fun there's a class called user so we are all we were also like exposing a firebase user to our ui and that is not a good idea so as a caption says here we shouldn't expose firebase's user to the ui so we need to have our own user that abstracts away the functionality or that that the current user at firebase level has okay so let's go ahead and do that so we're going to create an off user dart file in lib services auth a file called off user so i'm going to remove or sorry i'm going to close all the files that i've created and under services auth i'm going to then create an off user so i'm going to say off user.dark and in this off user then we need to basically start working with firebase in this case so i'm going to go to my notes just to ensure i'm telling you everything that i'm um that i plan to tell you all right so let's go in here and import firebase it's user import package firebase and is it in firebase auth i believe and then we're gonna say show user okay and as i've mentioned before this is a great way of just ensuring that you're not exposing too much of a packages classes to your current workspace except what you're saying is that firebase auth is isn't it maybe an entire dart file with its structures maybe thousands of classes now i'm exaggerating but a lot of classes but you are only interested in the user class okay so you could also like say as firebase off like that and then you would say show user and that will allow you so if i say test then you will be able to say firebaseauth.user you can also do that if you if you prefer to for instance ha prefix the user in this case that comes from firebase with the actual place that it comes from you could also use as some people may like it and i also do but i haven't planned to do that in in this particular file so do it if you want to the way that i'm doing it here so you can follow along with the steps that i'm providing for you in this course without diverging from from the point okay now that we've done the um import what we need to do as a caption in the case we need to create the actual class so let's say class off user and in here what we need is a field called is email verified now remember right now all we need from our off user is to know whether that email is verified or not so if you go for instance to our login view you can see that we have this code here and that signs a user in with email and password and right after that gets the user and all it does with that user says email verified and we're doing the same thing in register view i believe so let's go to register view and you can see in here and it says actually there we're not doing anything with the email verified all we're doing is just saying a send email verification so sorry about that so it's in login screen okay so let's go in our off user in here and say it has a property called is email verified okay so i'm gonna say final and bull is email and you saw that firebase has implemented this function this uh property as email verified i personally prefer to call boolean functions boolean getters in this case like a property of a class with is wherever i see that fit it's just because it makes a lot more sense for me at least to say user dot is email verified rather than saying user.email verified it just makes it more like complete grammatically is blah blah verified or is that so that's the reason that we're diverging a little bit okay um now you see this in here and we're saying it's email verified you can get help from visual studio code to create a constructor for final fields and even if you don't want to do that you could always just type it by hand you can say off user self is email verified sorry this is email verified and since this class it only has a property that you can set upon initialization and you're not changing it because it's a final field excuse me you can make your constructor a const excuse me again and it would also be good if you could basically let's say immutable as another try defining undefined i believe you actually have to import foundation in here now immutable basically is but immutable here i don't think we've talked about that before but it's just like an annotation telling that this class and any subclasses of this class are going to be immutable meaning that their internals are never going to be changed upon initialization so if you then go and create for instance class my off user and say extends the auth user and then you'll have a bull um let's say in here and you create a constructor for it so let's create a constructor for it so boom okay prefer declaring what is a const okay then we say const then you say okay well i want a boolean flag in here bull is blah and um yeah bull is blocked now you see it says null not non-nullable instance flab but it must be initialized let's just initialize it to false and and it says can't define a cons constructor okay then we're not going to make it a cons constructor and now you see that little warning here it says this class or a class that this class inherits from is marked as immutable but one or more of its instance feels aren't final so now you see what immutable means it tells dart that this class and all its subclasses need to be immune immutable they cannot have any fields that change so by removing this field then you get rid of that little warning and you can make this cons and the error completely goes away so now you know what immutable means okay all right great now we created that is email verified at a cons constructor for our off user let's go to the next point the next point as you can see here it says we need a factory constructor that creates our auth user from a firebase user and factory constructors are really useful for this purpose in that you have let's say object x and you want to create an object y from that instead of you manually gluing things in some sort of a middle layer saying now i take the object x and add some blah blah and fuse it together and then put object y you can put that responsibility on object y and saying that you need to be able to initialize yourself or construct an instance of yourself from this object and this is like a typical pattern that you'll see everywhere so um well everywhere everywhere but where you have the ability to do that so that's what we're gonna do now with a factory constructor so let's say we have a factory constructor here we'll say off user and we say from firebase okay as the caption says then we take a firebase user in here like that and then we say what we will do in here we will actually create an instance of our own class an off user given that user okay so let's say that we create an off user in here and a lot of user and it's email verified comes from user email verified like that all right so this shouldn't be they shouldn't be that difficult to understand so this creates this goes into this constructor you can see and it takes the email verified value of the firebase user and places it in this class so all we did is just we kind of like copied a firebase user and we made a copy of it into our own off user okay so we're not exposing firebase's user and all of its properties to our user interface all right that was a lot of information now let's talk about an auth provider as i mentioned in the beginning of this chapter and as you saw in the firebase console you will have the possibility to add various auth providers to your application when you're working with firebase so such as google and apple facebook and many many more okay an email and password combination like we're doing so all of those are providers what we need to do now is to create an alt provider class that encapsulates every provider that we may add in the future and creates a nice interface for them says every provider that our application can work with should conform to this particular interface okay so let's go ahead and take care of that now and i can see here we're going to create that file on the lib services auth off provider so we have lib services off but we don't have auth provider files so let's let's right click on auth and say off provider dart and go to my notes so what we're going to do in here then is since our off uh provider is going to work with our um it's for instance the the functions that we're going to provide for our auth provider are for instance a getter that gets the current user so that's not a function it's just a getter the way we're actually doing it in here if you see let me go to login view and you'll see in login view here this thing at the moment say firebase auth instance current user this is a getter so this is a property and returns the firebase user what we want is for our auth provider to also be able to provide us with the current user now remember we've abstracted away the firebase user with our own auth user which we just created okay so what we need is this abstract class that can return an instance of our off user okay so for that we need to import this off user into this dart file so let's just say import package this application that i've created as you can see in the title it's called my notes so let's go to my notes services auth and then auth user so that's the import statement as you can see in the caption i've written package xxx and that's where you need to put the name of your package in this case for me is my notes all right that's great now let's go and create an abstract class so i've mentioned this twice before but our auth provider dart file is not gonna have really is not gonna have any logic it's an abstract class though abstract classes in dart can contain logic but in this case our abstract class is just going to be a protocol or you may know it as interface or you may also know it as well an abstract class so let's go ahead and create that let's say abstract class auth provider and so the abstract class creation is done what we need to do is now give it like the ability to return the current off user okay so as the caption says we're going to say off user and get current user okay so we're saying any author provider whether it works with email password whether it's a google auth provider whether it's an apple facebook twitter whatever it needs to be able to optionally return the current currently authenticated user and that's what this optional site is here for okay and then what we will also need to do is to allow it to be able to log a user in okay so we're going to say we will have a function that completes in the future and returns an off user and it says log in like this okay and now we have to think what does this login actually require well in our case it requires email and password so let's just put email and password we're thinking that every author provider that we're writing is going to have an email and password combination of some sort you could say id and password but i'm just going to go with email and password for now okay so let's make these required parameters as well so i'm going to put curly brackets here and curly bracket here i'm going to say required stream email and then a required stream password like this okay and a semicolon at the end of that command s to save the file so dark formatter can do its magic and the reason where you see if we go to author sorry if you go to our login screen again and in here we say sign in with user and password you can see that it always returns a user credential now you may you may think how can i always return a user credential if the current email and password are actually incorrect and they don't belong to a valid user well the way that firebase is handling is that if you say sign in with email and password if you can grab the current user if he can't sign in that user with the information that you provide it returns it otherwise it fails with an exception meaning that it's saying that as long as you call me and there's no exception i will give you user credential if there is an exception well you need to handle that so that is a great way to avoid having functions let me close the off user as well avoid having functions that do like this that option on your return user so do your work in your functions return the user and return the object that you promised if you can't do that throw an error so you don't have to do this do this kind of a optional return okay for a the login function now we need to also have a function that can create a user so that imagine that it's for the sign up or um yeah what else do we call it uh register yeah so let's call it a create user so we say this also returns a auth user and we call it creates user like this and this also has all these parameters so i'm just going to copy and paste this you don't have to do that twice and a semicolon at the end all right guard formatter do its thing and then let's go and and create a function that allows us then to log a user out because that's what we're doing in the main ui of the application okay the log out it's not going to return any value as you can see in the caption here just a future void so we say future void log out just like that all right so that was simple and also we will need a function that can send an email verification okay so this one's also very easy it's just a future void and as you can see in captions we're calling it send email verification all right so how was that okay as i mentioned our office provider at the moment is just an abstract class so it's dictating an interface for any authentication provider that we're gonna add to our application we but just so you know we are only going to add an email author provider okay or sorry a firebase author provider but this way by creating an abstract class with an author provider as a name and then you create a concrete class called firebase auth provider you're able to in the future to extend this and add more and more auth providers all of which will follow the same interface okay so that's the goal but we're only in this in this course are gonna use firebase auth provider so uh just so you know as the caption says go ahead and create a a file called firebase auth provider in your services auth folder i'm gonna right click here and i'm gonna say oops uh and say new file i'm gonna call it firebase off dot provider.net now let's go in here and say um i'm gonna go to my notes a little bit here uh like that okay so this is gonna be like the juiciest part of um of this chapter we are actually going to abstract the way firebase authentication into our own provider so expect this file to grow a little bit in size i can see my notes it's going to go to about 100 lines of code but that's okay too so and um we can just get started with it and so as you can see in the caption we need to import a few of files auth user auth provider and off exceptions we need auth user because this sorry actually let me first explain why we need to import auth provider because our firebase auth provider is going to be a concrete implementation of the file auth provider or the class auth provider that we just created so that's the reason for that import the os user import is going to be because as you can see in the auth provider the login and create user functions they need to return an off user so that's why we need to import off users so that our provider can return instances of that okay and last but not least we also need to import auth exceptions because remember our firebase auth provider is also going to abstract away all the authentication errors and exceptions that otherwise happen at the firebase level into our own exceptions that we've created here off exceptions okay so let me go ahead and first import off user so package and this application called my notes and we have services auth and then we have off user okay so i'm gonna import that and i'm gonna copy this file then and this line and the next one is gonna be the off provider and as you can see in the captures we also have to import auth exceptions so those are the three imports now since we have our own imports and this file is going to talk directly with firebase we also need to import firebase of course so and let's go ahead and import and i'm going to actually copy that code so i don't have to type all of it because it's a little bit boring but you can see in the captions at least what you need to import the firebase off and you need to also import firebase off exception okay great so that's our imports um now what we need to do is to create the actual class and um as you can see it's going to be called firebase all provider and implements auth provider which is our own class so let's say firebase auth provider implements a provider just like that okay and now you can see you get an error same missing concrete implementation i'm going to change the layout of the screen so you see the code in its entirety and then what we need to do is to implement you see those function functions and getters that auth provider abstract class says that every class that implements it needs to implement those things as well so you may try to do those things by hand but i absolutely i i i'm not at all a fan of doing things by hand sorry about that so i prefer to get help from the editor to complete these things so i'm just going to say command dot and make class firebase off abstract create five missing overrides okay so there we go so visual studio code created all those functions in here and you can see in all of them it just says throw unimplemented error great stuff i'm gonna decrease the size of the font here go back to the same layout that we had before so the first thing that we need to do in here let's go ahead and implement this current user okay so this is going to have a lot of not a lot but it's going to have a bit of logic so i'm going to do this instead of being with a pointer and let's go ahead in here and try to get that user so let's say you see our job is now to get the firebase user and turn it into an off user remember our off user had a factory constructor so we need to call that factory constructor okay so let's just say final user is equal to firebase off our firebase and auth instance and then we say current user and then we say if user is not null and we need to create an instance of it as off users so we just say return off user from firebase user okay otherwise we return null like this so if firebase says there's a user then we create an off user out of that and we just return it okay that was for a current user it wasn't so much of code to be honest with you now what we need to do is to take care of create user which is this function right here so create user is going to be a little bit thicker to be honest so let's go ahead and first do a little bit of formatting in here so i like to always append a comma at the end of the last parameter of my function so that when i do dark formatter or dart format it's going to break all these parameters into their own lines okay because before it looked like this and it's not so clean in my eyes at least it's a preference thing okay so in here what we need to do is to create basically uh a user with uh firebase so i'm going to put this entire thing in in a try block and then we're going to catch firebase off exception and on firebase off exception catch e okay so just like that and then we're going to have a generic cache block in here like this all right uh now what we need to do in create user in the tri-state main statement we need to actually tell firebase that we want to create a new user so let's say firebase off instant and then we say create user with email and password okay so we have the email here and the password and we can see those parameters already there so we don't have to do anything so um but what we need to do here is you can first actually see yeah this function needs to return a value we're gonna fix this so don't worry about that but we also need to await on this because remember creating a user or email password is not a function that just returns immediately and this is one of the things that is absolutely beautiful about dart in that in the interface we didn't actually say that this function has to be async but you can in this concrete implementation make this function async so it's absolutely beautiful so async is not the part of the signature of the function but it has more to do with the internals of that function so in order to call this function with an await you see if we put a weight here we get an error we need to make this function async all right so great stuff all right so after doing that what we're going to do is to get the current user if the current user is there then we're just gonna return the current user if the current user after creating a user or email and password and no exceptions is not there then that is a bad sign and we need to return then one of our auth exceptions called user not logged in off exception okay so i'm going to close this so let's go in here and say final user is get or just user is the current user remember we already have a getter for a current user right here okay and it just gets the current user from firebase so we say here's the user if the user is available there is not null then just return the user otherwise you should throw a user not found or i think that's what we call the user not logged in auth exception all right that's for the creation of the user if everything goes fine except for this part now we need to go to our firebase auth exception and we need to handle a few things um so if you look at where in our register view in here we are handling weak password email already in use and invalid email so let's just copy these three things okay actually these four things because we have an else block in there as well okay so i'm gonna copy that code just do the same thing please so go to your registry and copy that code go back to your firebase auth provider inside the firebase off exception where you're catching that paste that code but remove everything that has anything to do with the show error dialog okay so at least we have if and else statements okay like this so you should end up with a code that looks like this now where there is a weak password we are actually going to throw our own error so we're going to say throw weak password off exception it is an email already in use we're going to throw email already and use authexception in case on invalid email throw invalid email off exception and if there is any other code that we don't know about we're just going to throw a generic auth exception and also if there is a final catch basically meaning that by calling the create user an email with email and password if there is any other exception other than firebase auth exception we also need to handle that and throw a generic auth exception there as well okay a lot of code but hopefully this makes our ui code easier to read okay so we're doing this for a good purpose great stuff that's for our create user i'm gonna fall create user uh if it allows me to fold the entire create user poof and i'm gonna fold current user as well so this is a technique that you can or not a technique that's just a trick you can do in your editor if it supports folding and unfolding just to make sure that it looks a little bit cleaner okay because now that you've written create user you may not be directly interested in all its details you may just want to know that it's there okay all right the next thing we need to do is to implement send email verification so let's find that function and i can see it's right here send email verification i'm gonna scroll a little bit up so you see like that i'm gonna go to my notes as well okay so what we need to do then is to incent email verification what we need is to also mark this as async because it's going to call an asynchronous function on firebase as well okay and we need to call the send email verification function on the firebase user remember our user doesn't have that functionality our user only has is email verified property so in here let's get the firebase user so i'm going to say user is firebase off instance current user and we say if user is not null then we call that function so we say await user send email verification i remember i think this was the future of void so that's why we're doing a weight on it and that is why we have the async tag in here okay now if the user is nil then we're gonna just say user is not logged in you cannot send an email verification from user who's not logged in okay so then you throw user not logged in off exception okay so that's our send email verification function let's then fold this function as well so we don't see its internals as the caption says now we need to go and implement a login login is just as important as creating a user i'm going to start by putting a comma at the end of password parameter here and command s in order to save it and in here in the login function we're going to do something very similar to what we're doing in the register function i can see in my notes by doing a try and then we say on firebase off exception and catch e and then we'll say catch any other exception okay so let's in in here then start by um telling firebase that we want to log in with those credentials so let's say firebase auth instance and then we say uh sign in with email and password so there's a function in there okay and i'm gonna put a semicolon at the end so you can see the code all right so that's what we're doing but remember again these functions are asynchronous so you can't just call that function and expect it to work it's a future of user credential okay so make your function asynchronous and then await on this function so we're going to do something very similar similar to what we're doing in register sorry in the create user in in that we're saying final user is current user i hope you can see that code yes i can see that you can see so in this in this uh code we're gonna take the exact same code that we wrote in um create user so i'm gonna expand that you can see here i'm gonna copy that code and you could do the same what we're doing is just making sure after signing in then there is a current user okay copy that code gonna fold this then i'm gonna bring it to the login and right after sign in with email and password i'm gonna paste that code okay so that's that part now you see now we have firebase authexception again to handle just like we did with create so let's go to your um login view and have a look at which and which exceptions we were handling so i can see here we're handling these i'm actually going to copy that entire code from login view you see a firebase off exception username wrong password etc and including the catch any other exception block right here copy that code and bring it to your firebase auth provider and replace let me actually see how it looks like yeah replace all of this with that okay and then remove your weights as we did before to be honest with you this this is just a lot of big talk for saying that we um need some code from another place to bring here so your code now should look like this so it says on firebase off exception and we're handling user not found wrong password off exceptions from firebase and a generic catch block okay so in the case of a user not found a firebase office session we're going to say throw user not found alt exception in the case of a wrong password we're going to say throw on password boss exception and any other case that might occur here we're just going to throw generic off exception and in here as well we're going to say throw generic with exception and thing i really like to do is you see in dart it's not yet possible to say that i want to ignore a variable in this case you can see that in this like where we have a catch we actually have to pattern match against an exception and then we have to assign a name to it and that name is called e inside this function so if i type e you can see it's an object however as you can see in the body of this function we're not actually interested in e at all we're not using it so in in other languages it is possible to ignore like in javascript python swift rust it is possible to ignore a variable and saying that hey i'm not interested in this value by putting something called like an underscore or something you can do the same thing in art the difference is that in dart if you say underscore you're not actually ignoring it that variable is also there but it's just called underscore in this case so you can see you can still call to string on it so you may want to do it or you may just want to leave it alone because you can see guard an analyzer it doesn't give you an error of any kind saying that yeah your pattern matching but you're not using it so it's up to you how you want to do it and i like to do it like this wow that was a lot of code um or maybe more like a lot of explanations so let's go to login and fold that and as you can see in the caption now we have to take care of the logout function and the caption also says that this function needs to be asynchronous okay and you know why because we're going to call a function on firebase in order to take care of the logouts so in order for a user to be logged out the user should actually exist so let's just say final user needs firebase off instance and then we're going to say current user and we say if user is not null and it's a user sign uh logout what's it called or what's it called oh we have to tell a firebase off so we then we say firebase off instance sign out the weight on it okay otherwise we say throw user not logged in so we're basically saying here that you cannot log out a user if that user doesn't exist okay or that user isn't logged in all right lots of code lots of description but that's okay we've now implemented an auth provider firebase auth provider okay which is a concrete implementation of auth provider now as the caption indicates here we need an auth service um now what is an auth service i mentioned this a little bit before but an auth service is also going to implement auth provider and in itself is going to take an instance of an auth provider as well but as you'll see in this chapter and in the rest of this um course you'll see that our our auth service is really just the provider itself which is exposing all the functionalities of the provider that we give it and it's not and it has absolutely no other logic at the moment okay but the reason we're doing that is for me to just to show you that you need to have providers and then you need to have services that they talk to each other and then this service can then expose more value to your user interface to your ui code than the provider does that's usually the case that the service fuses together a few other providers talk to few providers and at the end it grabs the data fuses together and provides that information to the ui now in our case that's not gonna be the case okay our firebit our auth service is only going to talk with our the given auth provider and expose all its functionalities to the ui but we're doing this exercise so that you see how you can abstract away various bits and pieces of functionality from the ui code so remember that that's the reason we have our auth service which we're gonna soon create okay so as a caption in the case here let's go ahead and create our odd service inside the auth folder here so auth and i'm going to create a new file here i'm just going to call it all service in this dart file then we need to create start creating our auth service okay sorry gonna go to my notes in here as well so what we need in here is to import a few things we need to import our auth provider and an off user so i'm not to explain this again so um package my notes and we have services off and we have and we need to import auth provider and copy this kind of code and then i'm going to say off news user i believe so um so let's have a look in here in the captions like that okay so we need to create now as you can see we need to create an auth service that also implements auth provider okay so um if i look at the captions here why is auth service an author provider i've already explained this to you but you can see it says but can have more logic so that's the reason okay so don't forget that so let's go and create a class of all service in here and it implements an off of the auth provider um abstract class okay now what you'll need to do what you need to know is that the auth service in itself isn't going to be hard coded to use the firebase auth provider what it's going to do is that it's going to actually take an audit provider from you and saying that okay i will then expose the functionalities from that auth provider to the outside world with the ability to maybe even change that data before it returns it to you but in our chapter and then the rest of this course it's not going to do that it's just going to expose the same auth providers functionality to the outside world so let's go ahead and as the caption says say we take an auth provider and we just call it provider okay we need to do then is to create a constructor for your auth servicing here so command dot on mac or control dot windows and linux and say create constructor for final fields and make it constant as well okay so now we have this beautiful little off service that takes the provider but as you can see it says missing concrete implementations and that's because we said our auth service is also an auth provider so we have to implement those auth provider classes overrides as well so let's add them in here as well but this time it's gonna be a lot easier uh to implement these functions because our because our auth service internally has a provider and all it has to do is just expose the functionalities of the provider in its own implementation all right so um as the caption also says we need to delegate then to our actual provider before we do that i'm going to do a little bit of a clean up here and i suggest that you do too and in places that we have more than one parameter let's go and put a comma at the end of the last parameter right here and there boom and that was it i'm going to do command s so that dart formatter formats the code a little bit better and let's just go and go ahead and expose the functionalities of our provider in our concrete implementations of the auth provider so in here we say provider dot creates user email and password perfect for the current user we return the provider's current user we say provider adopt current user for the login we then expose the providers login function we say provider login with that information and for our logout we do the same thing so i'm going to say provider logout okay and for sending you so say provider send email provider and notification great stuff that was uh that went really fast as you can see okay now um you see we've done a lot of code now if we go to our if if i change the screen layout a little bit better a little bit so you see the code better and let's go to our terminal the built-in terminal i absolutely love it in visual studio code that there is an integrated terminal and let's have a look at our git status you'll see that we have changed login view but also there is an entirely new folder here called lib services so if you then add all of that and to get status you'll see that we actually have done a lot of work so if i increase the size you see we've added all exceptions auth provider all service auth user and firebase auth provider plus the changes in the login view now um actually i don't know what did we change in login view so that's interesting to know if you go to the login view did we did we change anything in login view because at the moment i can't really remember if we change anything special in the login view so it would be interesting to actually see what we've done so if i go to my terminal here and if i issue this command as you can see here i'm going to remove that login view from the staging environment so like this paste it there and i'm gonna say git status and then i'm gonna say bit diff i can say okay the difference is that i have added firebase core in here which i don't see in the login view and also what's changed has this navigator been removed there's a lot of code in here that may have not been committed from the previous chapter that may be it so that may be the reason okay but that's all right as well so now let's get at all and let's then go to the next stage as you can see we've done a lot of work let's just make sure everything is committed this time okay so get status everything is added to the staging environment then i'm just gonna say git commit message and step eight this time and i'm going to push all those changes and get status i can see everything's committed great also let's tag our code because i believe the previous chapter we didn't tag anything but the one before that we tagged that step seven and that was chapter number 22 where we talked about error handling in the registry and going to the next screen after registration so we didn't tag anything in the previous chapter so now we're going to tag things as step 8 so let's just say git tag step 8 i can spell here and it push tags as well if you can say git log you will see get step 8 is there step 7 every step is there an initial commit is there as well which is step one and if you say git tag you'll see all your tags available as well okay so we've committed and tagged we've done a lot of work in this chapter and i don't think we need to actually drag it on for longer because yeah it will be unbearable maybe if it's too long now as we usually do which is the tradition here before going to the next chapter we prepare ourselves for what is coming as you can see in the caches that we need to migrate our existing code to using our own auth service we have an auth service which abstracts away the provider and we have a firebase auth provider but we still are not using that code so that's exactly what we're going to do in the next chapter and if i look a little bit in my in my notes i can actually see the next chapter will also be quite a long one maybe not as long as this chapter so maybe you'll need a cup of coffee or tea so let's do that and without further ado i'll see you in the next chapter hello everyone and welcome to chapter 25 of this flutter course in the previous chapter we talked about earth service and that was quite a big chapter we talked about cleaning up making sure that our authentication related code is in one central place we created the auth provider the firebase auth provider then we created our auth service and and we also ensure that both the service and the provider are conforming to the interface provided by our abstract class for authentication so um we call those the off service and the firebase auth provider and then our abstract class was called auth provider now we've done all that work but we haven't really even started using that auth service and that's what we're going to do in this chapter um the first thing that we have to do is actually making sure that we have easy access to our off service um you see the way we created the auth service let me bring the code here so we can all see change visual studio codes um layouts a little bit let's then have a look at our um let me see if i can resize this a little bit as well okay let's have a look here at our auth service you see that with the way that we created our off service is that it in its initializer or constructor however you want to call it um it is taking a provider so for us to be able to use our auth service every time you want to use our auth service we actually have to provide it with an auth provider which in our case is going to be the firebase auth provider which it resides right here so this could be cumbersome especially if you're working with firebase quite a lot in your user interface every time you want to use it then you need to say auth service initialize the auth service and then initialize your firebase auth provider and give that to your auth service so we don't want to do that every time and that is exactly why we need to create a factory uh initializer as you can see here in the uh in the captions so uh it says add firebase factory to officers and that's exactly what we're gonna do here so let's go to our auth service and as the code is provided for you just write it factory and i'm going to say auth service dot in firebase so the responsibility of this off service firebase factory here or sorry the the responsibility of the firebase uh factory here on our off service is to return an instance of our auth service that is already configured with a firebase auth provider so then we're going to say it returns an instance of auth service change the layout of the code here the screen as well so you can see it better and we're going to say firebase um auth provider okay so that's that um now you see i have a column here in visual studio code that tells me where the code is going to break some people even for one parameter in their uh dart code or flutter code they prefer to have a comma at the end of it so that it is ready to take new parameters in the future so if you do that then um dart format is going to break that code for you into multiple lines ready for you to enter the next parameter if that's your preference go for it but i have no preference here i just leave it like that when i have one parameter i just leave it in one line okay so before we actually go about uh starting to use our auth service we need to take a little trip back to the main dart file as the caption indicates here so you either go to the explorer but the way i usually like to do it is with command p and i say main dart and then i go there remember if you are linux or windows then you have to do control p okay so let's have a look at our main dar file and let's see if i can close these places firebase off firebase provider login the dart what did we change there save that as well let's go back to the main now so basically i just closed all the files uh because i just want to have them in our files so as the caption is is telling you here um our menu action and the notes view are right now spread just around in the main dart file and this is usually not a good idea because you need to as part of your journey into becoming a software developer you need to make sure that your code is clean and it's easy for other people to read now i'm not saying i mean i'm not a true true believer that the code has to be so easy to understand that even if you grab a random person from the street they have to understand the code because sometimes you need to make sure that the person looking at your code has a certain level of knowledge from before but with all that said you need to make sure that your code is easy to understand and read so let's make sure that the menu action and notes view are refactored and that they're in the right place and not just spread around in main dart file so as a caption indicates we're going to move our menu action into a new new folder called enums inside lib and the file name is going to be menu action dot dart and the caption was a little bit wrong it shouldn't be dark 10 it should be dart so i'm going to save the caption and bring it back up so it's with the right file extension so let's go and create that file i'm gonna go here into lib i'm gonna right click on lib and i'm gonna say new file and in the new file i'm just going to type ins and bring it up as well so you see it better or you see it at all enums and then menu action. okay excuse me let's just go and grab that menu action from there and paste it inside this menu action and save that file okay don't worry main.dart at the moment has a problem because menu action doesn't exist here anymore so we're getting some errors and that's okay we're gonna fix that so let's go now to our um to the main dark file again and we have to clean up this notes view and as the caption in the case we're going to move it into lib views notes view okay we already have the views folder remember from before all we're going to do is just to move this notes view into its own file so i'm going to right right click on views and i'm going to say notes view dot darts okay let's go to main guard grab the notes view and it's state so from there notes view stateful widget and i'm gonna grab all of that and we're gonna even take the show log out dialog with it and bring it to note2 and paste that there okay so now we have a lot of problems because uh in an empty dart file as i've mentioned before there's no material import so i'm going to do the material import now so command dot and say import library package flower material and that is going to fix those import those errors for you now this file doesn't have it hasn't imported uh menu action so let's fix that as well with visual studio command dot and get help from visual studio code to automatically import our menu action dart file okay so that is also fixed and also remember now in notes view also right now is using firebase off and we're going to fix somebody into this chapter so that note2 isn't or any of our views none of them are going to talk directly with firebase so that's going to be fixed by the end of this chapter but for now let's go ahead and clean this up and make sure that firebase auth is imported and also remember login route was used here when we log out of the main interface of the application so when we log out then it sends us back to the login route and that is defined in our routes dart file here so let's import that too excuse me all right so that was a lot of work we've we've done that now so we're done so i'm going to save this notes view dot dart and now as the the case we need to go back to the main dart and remedy this issue which we have and we need to import notes view uh get help from visual studio code or your favorite editor or if you don't have this functionality in your editor if you're using vim or something you may just need to import that by hand and the import is just the package name of your application views notes view okay so i'm gonna get help from visual studio code to do that great so um now let's have a look at something that we actually forgot in the previous chapters um you see we've done everything in our off service if you have a look at our auth service it has almost all the functionalities that we need it has create view sorry create user it has current user it has login log out and send email verification but there's one detail that we forgot about let's go to main dart and have a look at it you can see in here our entire main dart uh like the home page build function is built around a future builder that i i know i'm saying build quite a lot maybe i should say it's revol it's revolving around a future builder which in turn initializes firebase you see it calls firebase initialize app and now that we want to move away from our user interface interacting directly with firebase we also need to remedy this this user interface it shouldn't go to firebase directly it should ideally go to our off service and that's what the caption says so let's now go to our auth provider abstract class so let's close all these files make sure everything is saved let's go to our off provider and make sure that we have a function there and let me actually bring up my notes that says initialize so we're going to say future void initialize okay remember now that we've added this function to our auth provider we're going to have problems because both the firebase auth provider and auth service they're they're conforming currently to the author provider abstract class and adding a new function to this abstract class means that we're gonna get two errors indicating that this function isn't implemented in firebase auth provider and in our auth service so we need to fix those problems you can see they're actually highlighted as red here okay um let's go then to the next caption and i'm gonna get rid of that bottom view so it doesn't bother us so let's go now as you can see in the firebase auth provider and overwrite initialize and make it async and call initialize app on firebase so to in order to do the firebase initialize code we need to have a look at our main dart and see how that is done at the moment you can see it is called firebase initialize app so i'm gonna grab that code and i suggest that you do the same thing i'm just gonna copy that code for initialize app and let's then go to our firebase auth provider and get help from visual studio code or android studio in order to complete that one missing override for initialize function and i believe it gets added here somewhere or it didn't where did it go we should have an initialize a missing concrete create one missing override initialize i still don't see the missing i'm gonna do that here myself future void initialize like this okay and uh what we're gonna do as the name indicates it's gonna be an async function here and what we need to do is just to save firebase initialize app so um and we're gonna await on this so like that and remember we have we need to have two imports here and one is for the firebase and the other one is default firebase options so let's get help from visual studio code to import those firebase core and import firebase options dark file which if you remember when we set up firebase initially was brought into our application from the firebase cli so is is not a file that we've created ourselves except it's the firebase cli that created this for us okay here now it says annotate over members and that's exactly what we need to do so let's just say over right like this and now we have initialize uh over member of our author provider inside firebase author provider so basically all we're saying is firebase auth provider implements initialize function and it has actual implementation okay all right we have one error left and that is inside auth service so let's go to auth service and we'll have the exact same problem here and says missing concrete implementation so i'm gonna see if i can get visual studio code to add that implementation and it added it here initialize okay so in here what we have to do is just to delegate this function to the actual provider so we're going to say provider and we're going to say initialize just like that all right so this was the easy one and if you don't remember from the previous chapter or maybe you jumped over the previous chapter i don't know how you ended up in this chapter if you haven't watched the previous chapter i strongly suggest that you do that there is a reason we have our off service that implements auth provider and the reason behind that is that usually services have more logic in them than what they bring into themselves so if a service has two other services connected to itself then it may actually take bits and pieces from the service and other bits and pieces from another service and fuse them together with some extra logic and that is exactly why the author services as an odd provider so the goal for us is to allow the officers to do more work than an author provider even though right now only thing it does is just delegates all its functionality to the auth provider and remember you could also see make sure that i mean if you don't like this implementation you can for instance remove this and then basically remove all these functions and by doing that you're just saying that an auth service includes an off provider and that's all you're doing or you could completely kill you your off service so it's up to you but if you're following along with this uh with this course i suggest that you keep it the way it is because there's a there's a point to it so okay now that we've done that uh it's time to do some cleanup and this is this is a very exciting part of this uh chapter because we now have our auth service and our firebase auth provider and in and additionally we have an off service firebase factory which allows us to anywhere inside our code we could just say autoservice.firebase and in that way we get access to our um firebase auth provider inside the auth services so it's it's really magical you're gonna see it soon so i'm going to close all files here ensure everything is saved then as the caption indicates i'm going to go into main art file main dart and as you can see it says remove everything related to firebase and replace with auth service by importing auth service okay so one way of doing that is just to ensure that you go and kill it from the source so you can see here we have two firebase imports and if you remove these two firebase imports which is my preferred way of usually working with software is that i try to like remove something from its source so now that i've removed those then visual studio is telling me that hey you're using firebase in two places you need to fix this because you don't have the imports then i know okay here are the two places that i have to do my refactoring in okay so as you can see here it says firebase initialize app and we need to make sure that we're not doing that anymore so we're just going to say in this case our future remember is um it's auth service and since i haven't imported that yet visual studio is offering to auto import it so i'm gonna say yes please um it's auto imported now but if you don't wanna if you're you're working with vim or some other a text editor that doesn't have that capability you could import that in this way per package the name of your package services off auth service dart and i just noticed that this is another firebase import which i'm going to remove now excuse me so auth service now we want to tell because we're using firebase we're going to say auth service dot firebase and in here we're just going to say initialize okay so that fits in perfectly and in here you can see we're using firebase um instance firebase auth instance current user in this case we're just going to say uh off service dot our base man current user just like that okay and now remember odd i talked about this in previous chapters but i prefer to have boolean flags prefix with the word is whenever that makes sense and in this case you can see firebase implementation had email verified but we have is email verified so i'm going to say is email verified like that all right and s or control x and linux and windows a command is on on mac to save this file and it looks fine right now but we're not really done um we also have problems in our login view i mean problems not errors or warnings but problems in that we're using firebase directly and we're going to the firebase auth directly in our login view and we need to fix as you can see the caption system login view remove firebase and replace with off service okay so let's go to uh to the source and remove firebase completely from your login view command s and now you'll see we have a lot of problems here and one two three yep that was it so three three places that we need to fix so let's go ahead and fix those places because yeah um there's a lot to handle here so we start by this one at the moment we're saying firebase off instant sign in with email and password and what we need to do is just to uh call our off service so we're gonna say auth service and auto imported and auth service has firebase auth provider and we're then gonna say assign in or do we say login yeah email password okay so i'm gonna i'm gonna take this code the way it is and i'm not paste then them in here so now we're saying auth service firebase login okay then we're seeing here that we're getting the current user and the right way now to get the current user is by saying off service dot firebase current user and email verified should be ms email verified okay so now we fix those problems in this area by going to all the search instead of going directly to firebase okay that was that now we need to start looking a little bit at our error handling and you can see here we have on firebase off exception so we need to fix these with various um other exception handlings not firebase auth exception but now remember we have our own exceptions in auth exception start and these are all coming from exception but what we're going to do is we're going to have like on blah blah for various of those exceptions as you'll see soon so um i'm gonna what i'm gonna do is i'm gonna take this code and keep it the way it is like that and i'm going to add new on statement so um let's take care of user not found so i'm going to say on user not found exception and you can see that it says user not found exception is an exception that we created manually but it's not imported here because it was inside the auth exceptions dart file so i'm going to say visual studio code please complete that and also import it for me okay so say in this case then we have to do show error dialog so grab that code and place it here okay then we're going to say on what else do we have wrong password because it's this thing i'm going to say on wrong password of exception and go in here and grab then your show error dialog from here and place it there okay that and then we also need to have the on generic auth exception so on generic auth exception and we do this show error i like the way it is here so then we go and bring that here and you can see on generic error off exception we don't have any specific like information like any e or anything to string so all we're gonna do in here we'll just say we're gonna say authentication error okay and then you need to go and remove the other catch blocks so your code should basically look like this okay so a try block and then three special exception handlings one after the other great command s on your login view now you shouldn't have any problems in your login view and there's no import of firebase in your login view just as it was in the main dart file let's just make sure that there's no firebase import here either firebase yeah firebase yeah no imports of firebase great [Music] and as the caption now says we need to go to register view and remove firebase and replace with auth service now that we've done the same exercise now for login view you should now know basically what we're gonna do in register view we're gonna go to pretty much the exact same thing we did in login view except in registry removing firebase from the imports get all the errors that we're going to get and after we get those errors we're going to fix the problems in register so let's go ahead and do that let's go to our imports there's firebase imported right there we're going to remove that now we have probably quite a lot of errors yeah that's good and let's go then and fix that i'm going to go to my notes just to ensure that i'm following all the notes that i was supposed to tell you about then we don't create user with email and password in our auth server so let's just say all service and it's not imported so let's auto import it dot firebase and we're gonna say sign and what do we call it create user email and password on the end of the last parameter grab the code and replace your firebase auth create user email and password with our auth service create user okay and in the place where we're getting the user let's then say auth service firebase and we're gonna say current user and now we have send email verification but i think we called it some something else we said and oh we didn't implement the send email verification or did we let me go to auth service and um send email verification yeah it is right there so i'm gonna oh i see because previously what was happening is that firebase implements send email verification at the user level but we don't have we don't want that anymore and our user doesn't have that functionality actually our user has just a boolean flag so what we need to do in here we're going to ask our service to to send that email verification so we're going to say fire and auth service and this send email verification just like okay all right then we need to fix these exceptions as well because as you saw in the login view we don't have firebase auth exception in this case like we've removed the ui's ability to talk directly with firebase by removing all the imports so now we need to make sure that we handle exceptions just like we did in the login view okay so let's go ahead and say um on each password because i think that's the first one that we handle so um i mean you see almost the entire screen is now red and that's one of the downsides of using the extension that i talked to about during one of the first chapters of this course where i'm using an extension called air lens and air lens extends and expands all the errors that would otherwise just happen with little icons next to the lines it's expanding them into their own separate lines and it kind of makes the code look a little bit angry at times when you're making drastic changes to your code but don't worry about it just have a look at your syntax and kind of see that yeah i'm kind of doing the right thing i'm going to fix it soon so don't be intimidated by all these red flags in here okay or these red lines so let's handle weak password exception now it's going to be a little bit quieter here okay then grab your show error dialog from there and that's for a week password put it here like that and um then we need to handle um our email already in use on email already in use off exception and we're gonna then take the code from email already and use which is just a shorter dialog right there put it there okay like that um and we need to also handle invalid email so i'm gonna go in here and say on invalid email off exception let's grab the code from invalid email off exception and and and that part is done as well also we need to have on generic als exception so let's go in here and just say on generic auth exception and let's just handle that shoulder dialog and actually this is what we did for the generic auth exception so i'm just going to grab that code put it there and since on generic off exception we're not accepting any e so we're not saying on catch like e like that we could have done that but we're just ignoring completely at the e and in here and we're just gonna say failed to register and then let's clean up the rest of the code remove the other cat statements okay so your code basically is going to look clean like this now so you have a try block and then you say okay i'm trying this code right here create user if weak password auth exception happens do this if email is already in use do this if invalid email do this or any other auth exception do this so it looks cleaner in my eyes at least the way we've done it now than the way we've done it before in that before we were going to firebase and firebase do this do that on firebase auth exception do this otherwise so now the only thing we're doing is going through our auth service and handling auth related exceptions and that's it okay all right um now that we've we've done our work in the register you can see there's no errors in the register we need to go to notes view as the caption indicates so i close register view now let's open up our notes view and see what we are doing with firebase and notes view so do the same thing like we did before remove firebase as one of your imports so you get the you get the idea like an overall idea of what is happening in here and how we're using firebase and i can see the only place where using firebase in notes view is firebase off instance sign out that's good it's just one place but we have to fix that too so let's then go um sorry i'm just gonna bring up my notes as well um we're in notes view okay so let's just then go to um here and we're gonna we're just gonna say off auth service all right and then we're going to say log out i think we call it and we need to wait on it okay like that and it's bad so what we could do now we've removed firebase from there as well and let's then go as the caption indicates we need to now go through the entire app and make sure that everything is working as expected but before we do that let's have a look at our views and make sure none of them is importing firebase so i can see login view is not importing anything related to firebase meaning that it's not using firebase let's go to notes view no imports related to firebase either not using firebase or at least not using firebase directly remember it's using firebase but through our auth service okay so no imports from firebase here either and we have our verify email view which at the moment i can see verify email view oh i see that we haven't clean up our verify email view and that's something that we also need to do so we forgot about that let's let's take care of that okay so let's go in here and remove this firebase auth from here as well i'm gonna go to my notes here okay so let's have a look at that now let's say that uh send email verification shouldn't be there so let's just then say fire off service um firebase oops firebase a current user and i can see you see here it was using the current user just to send the email verification but we don't do that anymore we just because send email verification is not at a user level anymore when we've developed our off service remember so we'll just say send email verification like that await all right and then remove those two lines of code which were just getting the user and sending an email verification remove those and and to answer you i hadn't planned for this i can actually see in my notes i hadn't uh fixed the verify email view and that's why i'm not showing it in the captions and that's completely okay i have to improvise as well sometimes so let's then go ahead in here in them in the text button that says restart as you can see here that needs to just sign the user out so let's just say off service base log out and make sure that you wait on it okay just like that and remove this line of code as well so verify view now doesn't have any imports to uh from firebase either and i believe those were are all of our views except for also main let's make sure there's no firebase imports here either perfect so now we're done with this and what we could do as the caption in the case we're going to do a hot a restart here and let's see if things are working yeah and i'm just going to say restart here and let's see the current state of the application i'm going to bring up a firebase console go to my notes application here authentication and i can see i have two users here okay so i'm gonna i'm just gonna say pixelityab.gmail.com foobarbass and let's say register and then it should give us an error saying email is already in use so email is already in use let's go in here and say pixelityab gmail.combarbaz and i remember from the previous chapters this is a user that's already verified his um email address so by pressing login we should actually go to the main ui of the application so logout should work as it did before and let's go then to the uh and try to log in with the user and that's i think hasn't uh verified his email address so you can see then we're getting sent here verify email and then we can press the send email verification which in turn then sends the email and to the user so that was a lot of information and some improvised edition as well in this chapter for the verify email view that i hadn't planned for so it's good for me to know as well that sometimes i can miss things as well but now we haven't missed it during talking about it in this chapter so let's now wrap up this chapter we've done quite a lot and the main goal of this chapter is now we've achieved that because we wanted to go away from using firebase directly in our ui and going away from that using our auth service for everything related to firebase and that's achieved so very well done now what we need to do is as we're doing in other chapters we need to uh commit and tag all the code that we've done because it would be horrible if we lost all this code for some reason so let me change the um layout of the screen here and i'm going to make the browse the editor a little bit bigger so you see it better and i'm going to go into the terminal which i absolutely love in visual studio called the integrated terminal and you can see that in the previous chapter we had committed and tagged our code as step that's step eight now we need to commit as step nine first let's have a look at status and get add all status and we say git commit and we say step nine okay and then we say git tag nine as well and we first push our commit and we say good push tax all right that's pushed as well well done great job we are done with this chapter and as it is uh for the case for other chapters i've talked about we usually talk about what we're gonna do in the next chapter at the end of the current chapter so we're done with auth service it's working fine but what we don't have are some um tests you see there are three different types of tests that you can write in flutter unit tests integration tests and widget tests now a unit test is where you for instance try to take your current off service and then you uh want to just say okay auth service log in register do this do that and given this condition i expect you to do this now our auth service is working quite well but we can't be 100 sure that it is working as it should and let's say you're working inside a team and there are three other people working on the same code base with you and you work on the auth service and then you committed everybody reviews the code or the way i like to do my code is to a pair program or mob program so there's no code reviewing because everyone's working on the same code at the same time so it depending on how you're working inside your team then you send your code then two weeks later a new developer comes in changes your auth service and to and they change the service that it makes sense to them but then they break your code so maybe for instance email verification screen stops working because they change the code so that it's not executing the logic the way you thought it should execute the logic so that's why we need tests to verify that our um the way we design software is actually uh is the way that it should perform its work so that it's not missing any points and that's what we're going to do in the next chapter so um grab some refreshments and i'll see you in the next chapter hello and welcome to chapter 26 of this flutter course in the previous chapter you saw that we started using our auth service in our user interface code so we're not going against firebase directly so we removed all the imports to firebase in our user interface files in the login register main dart file and um notes view and also verify email view and we have a good working auth service however what we're missing are some tests and tests are one of my absolute favorite topics when i talk about software development because they make your code a lot more robust than just writing the code and leaving it in there and i understand some software developers may look at things as black and white saying that you have to have codes or you don't have to have codes but i'm more of a grayish person in thinking that well you have to be realistic sometimes you if you're for instance writing an application for yourself in a hackathon for instance and in in your you're in time pressure and you just want to get something out well that's not the right place to write a unit test if you're in a hackathon but if you're working with a company and they and you're getting paid to write good software and you're getting paid to write your tests as well to make sure everything's working out as it should especially if you're a back-end developer software like a front-end developer then you will need to ensure that your code is tested properly so i'm going to bring up the caption here about why we actually need tests and especially unit tests um and we're going to talk about the different types of tests in a while but let's just talk about unit tests um i mentioned in the like the outro to the previous chapter about what unit tests are and why we need them and for me the main reason having a unit test is to ensure that if you if you think here's the auth provider we left it in a state that well it's working okay code codes on code working so it's working but what if a new developer comes into the project and tries to change some code so that it works for her or for him but unintentionally changes it changes the code so that it's not working for us the way that we intended it so that's why that's one of the reasons we have unit tests okay um so that's what we're going to do in this chapter and i completely understand that this you if you're watching this of course you're probably sitting somewhere in a calm area a calm room and you're watching this course yourself it's the chat i think the chances of you watching this course with a group of people are quite slim so um and chances are you're just following along with the course and you're trying to write an application or release it to the app store or play store and play store so maybe you're not so interested in making sure that your auth service is actually tested and i completely understand that but i'm basically designing this course for people who are trying to become also good software developers so if you're coming as i've mentioned like one of the personas that i developed this course for are designers so if you're a designer have no background in flutter development you may also be interested in writing tests for your application especially if your goal is to go into a bigger organization and actually get a job as a flutter developer or as a software developer so given that background you should know what tests are what unit tests are integration tests are and what for instance widget tests are in flutter now i need to also mention that there's something called a tdd or test driven development and the right way of actually doing test driven development is to first write the tests and then you write your software at the moment we're doing it the exact opposite because i didn't want to complicate uh things as we're going because i have this as i said i designed this course for someone who's probably new to flutter development or software development in general so like going into test development test driven development directly and then writing our off service probably would have complicated things more so in for the sake of simplicity we wrote the code and then we're writing the test but just so you know if you're if you hear people talking about tdd tested with the test driven development what they mean is that you write the tests and in the writing of the tests you come towards the conclusion of how the interface of the class you're actually writing the tests for should look like if you're working with classes so test driven development is there's very important and we should be aware of it how to use it and if you're working in a software development organization you should do test development test driven development if time allows and if um all the constraints are in the right place for you to actually do tests and as i said i look at things more like in a not in a black and white um vision more like a gray vision i say that you should do tests but that is again something that is completely up to you and up to the situation that you're in so just be aware of what tdd is and that the right way of doing test driven development is that you first write your tests and then you write the interfaces and the code that the tests are actually performing their tests on there's lots uh lots and lots of resources online about tdd and what it actually means how it should be used tdd flutter as well so i strongly suggest that you have a look at those resources as well and maybe perhaps after you've gone through this chapter and done like the basics of doing tests now um you see we have time limit in this course because this course can't go on for hundreds and hundreds of hours um first because i i wouldn't probably be able to put so much time i know that this course is already gonna go over 20 hours of time but it is it is going to take a lot of time if you want to go and cover everything and all different types of testing in flutter so for the sake of simplicity and making sure that you follow along with this course without dropping off and getting scared of all testing things that we're gonna do i'm gonna give you like the basics and i'm gonna give you the building blocks that you're you need in order to be able to carry on later on your own and write more and more tests so i just know that the reason we're dedicating this chapter to testing is to make sure that everybody understands that testing is very important but also we are not going to have many many many hours just to focus on testing though it is a very important subject now let's talk about different types of tests i mentioned this in the outro to the previous chapter and but i'll mention it here in case you've jumped over that chapter which i don't recommend and if if you talk about different types of tests in the flutter you should know that there are unit tests widget tests and integration tests and let's just quickly talk about what these different types of tests are well um let's go and talk about the concept for instance of a class let's say you've created a class called auth service which is the case for us and you want to write some tests for this class now this class is very isolated in its own in its own like it is it has a set of function functionalities functions and it has a getter called current user if you don't remember that let me just bring it to the screen so you see better um so let's go to our auth service it conforms to and implements the auth provider it has a constructor it has a factory constructor here as well and it has all the functionalities that are provided by the auth provider because it implements auth provider so i'm gonna actually increase the size so you see better so um this is a unit of itself so it's a an isolated piece of code that talks with an auth provider and then it gives us uh basically mirrors the functionalities of that author provider which in in this case is that in the firebase case is the firebase auth provider so it doesn't have so much functionality but it has functionality good enough in order for it to be tested and it's actually important to test it just to make sure nobody unintentionally changes this code without without consulting with us or without like and making sure that their changes aren't gonna break our code so that's unit tests so you have a unit of code you have a piece of code isolated and you want to test that piece of code and to ensure the different functions inside that code um are working as they should so that's just like a general idea of what a unit test is now a widget test as its name indicates is a way for you as a software developer in order to make it as a way for you as a software developer to make sure that your widgets like the ui that you are creating is working as a shift for instance if you have a login view in your application and this login view allows the user to tap on a button in order to log in and you're saying that okay in the ui i'm going to make sure as soon as you press the login button until the user is logged in that this login button should be disabled okay so that's a piece of logic that you thought about good idea you put that code in there but how do you test it how do you make sure that the login button stays disabled until login is successful that's where widget testing comes into play so widget testing is some sort of uh like an end to end test and by that we mean that your widgets are probably talking with your services and with your providers so your widget for instance the login widget or the login screen upon pressing the login button is gonna call into your service in this case the auth service and it's going to go into this login function this login function in turn is going to talk with a provider the provider in turn is going to talk with the firebase code which in turn is going to talk with the firebase backend so you see the layers are stacking up ui is here the button is on the ui ui is talking with auth service here auth service is talking with the provider the provider is talking with firebase firebase is talking with the firebase backend and maybe the backend is also talking with some other services so that's end to end it's one end and the other end is right here so you are basically by writing widget tests you're doing end-to-end testing in a way okay so that's widget tests the other things are integration tests you see an integration test is where you for instance have a service which we have in this case the auth service and the auth service is in this case the auth service constructor or the factory constructor is talking with firebase so if you test our off service the exact way it is in that you go and say auth service firebase and then you issue commands against this auth service firebase you create a user you sign in with the user you log out you send an email verification if you're doing these tests you are actually doing integration tests so you're because you're making sure that the code is also working end-to-end but there's no ui involved so uh but i mentioned i mean you're now thinking okay what if testing auth service the way it is is integration tests how come you said in the beginning of this chapter that we're going to do unit tests and that's what we need to talk about now because you see in this unit test exercise that we're going to do in this chapter we're not actually going to call firebase we're going to call we're going to do something called mocking i don't know if i've actually mentioned some something here yes i can see that later i'm actually going to talk about mocking and mocking in english it could mean that you're making fun of someone and that's not this and what we're talking about here mocking is kind of like you imitating um a real service so imagine you have the auth service the off service has a firebase factory talks with firebase and it turns talks with the firebase code and then talks to the backend we're going to get rid of all of that pipeline and say we're going to test off service but we're going to give it another provider a provider that we control you see the fire the firebase auth provider has a lot of code in it so we can go in there let's go in the firebase auth provider it talks directly with firebase but what if we could create an auth provider that conforms to auth provider and then write a lot of logic in that auth provider and provide that author provider to the auth service now all of a sudden we have an auth service that delegates all his tasks to this mock um auth provider that we control the code for so we know exactly what the sign-in is going to do we know exactly what the sign out is going to do or log in and lock it depending on the terminology that you like to use so what we are going to do in this chapter is mocking and i'm going to explain that soon so let's just jump over that for now okay um the next thing that we need to talk about are dev dependencies if you're coming from like a node background if you've worked with nodejs or express you know already about npm which is the node package manager and you know what dev dependencies are in there if you're coming from an ios background there isn't much of a dev dependency to be honest with you except if you're coming from an ios development background then you know when you're writing your tests those test frameworks etc that you bring into your test target there are inside their own target so that they're not shipped with the final product if you're not coming from any of those backgrounds and you just want to know what dev dependencies are all explaining now you see when we're working with our application if we go to our pop spec yaml you'll see that we have a section here called dependencies and at the moment we have dependencies on various libraries for instance firebase core firebase auth cloud firestore and firebase analytics these are the dependencies or libraries that we're bringing into our application which if you think this is our application these are the various libraries coming in and then we're at the end actually at the end of this um course we're gonna send our application to app store and google play store when we create our application to send to these respective stores we're bundling the application and all the dependencies together and sending this as a complete binary to the respective um app store however you also have a section here in your pop spec yaml called def dependencies now dev dependencies are dependencies that you use and bring into your application only during the development of your application meaning that when you ship your application which is a term used for saying that when you create the application and post it to the respective app store for instance for review then those dependencies aren't actually packaged inside your application so they're only inside your application while you're developing it and as soon as you package it up and send it for release then those dependencies are not going to be packed inside the application all right so those are dev dependencies now let's go to our testing here so as you can see here we need to bring tests into our into our flutter application to make sure that we can actually run our tests so you will see here flutter test is already included i'm going to show you the command that you'll need to issue in terminal in order to bring it manually as well and that is if we go in here and just type flutter pop add test dev all right it's doing a pop get there okay this job is done now now let's have a look in here and you can see now we have a dev dependency called test and that's how you bring it into your application using this command so i'm going to bring it up again just so you see it flutter pop add test and and a dash dash dev if as i said if you're a node node.js developer you'll know this from npm d which adds it as a development requirement or dependency to your application so i'm not going to assume that you brought in this test package into your application with the command that i provided here for you in the terminal so if then you look at your pops back yaml file so i'm going to bring this down if you look at your pop spec yaml file inside dev dependency then you should have this test package only inside your dev dependencies if you see that is brought into the dependency section that is incorrect it shouldn't be there and that is because you've missed perhaps adding the dash dash dev at the end of your flutter pop add test command so if you do it like this then test is going to be added to dependencies and that's incorrect so make sure that you fix that error okay so let's go to the next section and talk about that now if you bring up your explorer you will notice that if you go to your test folder the entire test folder at the moment is marked as red and and uh actually it's not marked as red like an email it's is is rendered in red color that's what i mean so it could be um maybe heard in in the wrong tone so if you go in there that folder was read and then if you click on on this file which is called a widget test that file is also red has a lot of errors here actually no it has one error because it's creating something called my app so what we need to do in here because we don't need this existing test you see this test was created for us when we created our flutter application we need to get rid of it okay so let's go in here and right click on it and just say delete and that file is gone okay so that's the first thing that we have to do and collapse this leap folder here as well now what we need to do here as a caption indicates we need to create a new file called auth test dot dart okay so let's go ahead and do that under the test folder so let me go ahead and do that right now under the test folder right click and say new file and then call it off test dart all right okay and what we need to do then in this off test start right now this function is completely empty so let's first add a main function in here like that and you can see as soon as we add the main function in here dart is intelligent enough to give us a run and a debug functionality here and that's displayed in visual studio code i think android studio also does the same thing i don't think vim is availa is able to do that it may be vim is time and time again has surprised me with all this uh amazing capabilities uh but depending on the um on the tool or the text editor or the id that you're using this could be different but don't worry about it we're not actually going to click on these things so if you don't see these things in your text editor you don't have to worry about that so now that we've done adding the test package now that we've imported test packages that depends we also need to import it so let's go in here and say import and get rid of this editor sorry explorer on the left hand side and i'm going to say if we import a package called test and there's a file in there called test start so now we're ready basically okay all right um now you see you may not have noticed it but i have this application already running on my actual android phone as we've done in the previous chapter so i never killed this application without a reason it's always running on that android phone i can always bring it up with scr cpy so i can see right here that is running without a problem however remember one of the previous chapters one of the first previous chapters when we talked about adding firebase to our application i think it was chapter five or six it was very early in the course when we brought in firebase we need to we needed to kill the application meaning that we needed to terminate the application and run it from scratch so depending on some dependent actually no i don't think it's depending when you bring in a new dependency in your project you need to always ensure that you rebuild your project so you cannot do hot reload and hot restart because some of these dependencies they actually need your application to be compiled from scratch and then then be brought into your binary so hot reload and hot restart aren't going to actually like be able to bring those dependencies yet at least into your flutter application so what i need you to do is to stop the execution of your program and then let's go in here save these changes then let's go and say main.dart and let's run the application without debugging and let's see if this is going to launch the application correctly on the right device as well and i can see yes it is going to run it on the correct device i change the screen layout a little bit here as well so let's just then wait for uh this gradle belt to finish doing its work it might take some time depending on the changes that you've made to the application in this case we brought in a whole new package called testing to our application so it is taking its time and that's completely fine and i can see now it has run our code without a problem great stuff for this chapter i don't think we need our um device with scr cpy if you're using ios simulator i don't think you need it if you're using an emulator i don't think you need it either so we could just get rid of it so we don't have to display it on the screen but remember my application is still running okay so um let me get rid of this here get rid of the widget inspector get rid of the main dart and let's go to our auth test dart file in here okay now one thing that we also need to fix before we start writing our tests is this little functionality here this little guy in our auth user if i bring up off user here you'll see that it has the way we left it is we added a um we added a member variable to this off user immutable class here called is email verified and the way we're constructing this auth user if you see here we're saying off user just give us this william so if from anywhere inside your function and you have a if from anywhere inside of your application you want to create an instance of off user you'll probably do like this off user and then you have to pass that boolean is email verified however you'll see that parameter has no name it's just a true or false if i as a programmer see auth user true obvious or false i don't understand what this true or false is what does that even mean does that mean the auth user is turned on is turned off what does it mean for that dart has the capability to give you required named parameters and that means that instead of passing true in here you will be forced to write off user his email verified true or false like that so in order to do that as the caption indicates we need to go and make this a required parameter and the way to do that is to wrap it inside curly brackets like this and then prefix it with the word for the keyword required so after you've done that and this function is not going to work anymore because this parameter is missing so it's email verified and we're gonna pass this value right there okay and let's just move that remove that function so now we've achieved what we said we're gonna do now um because you see we're not gonna we're not actually you may think that okay we've changed this parameter to required so where are all the errors in our code why didn't anything break and that's one of the beauties of what we've done so far and that we've abstracted away so much code that the code is a lot more robust now so because nowhere inside our application we're actually creating us users except from this factory function the only place we have to fix this is email verified is inside this factory function so to me that's beautiful because doing something like drastic by adding a required parameter to a class it didn't break anything so we're just good to go okay all right um now this is the point that i mentioned previously that we need a mock off provider all right in order to do a mock author provider i need to go a little bit more into what mocks are and why we need them you see in software um we have especially in testing as well or even as the app architecture level or software architect architecture level we have something called dependency in injection dependency injection just quickly explaining it is very similar to our auth service let's have a look at our off service here you see off service is dependent on an auth provider and it's not just making the assumption that it's auth providers always firebase it provides a factory for firebase but it's not making an assumption about that hey i'm always locked to firebase auth provider this is dependency injection so this off service is dependent on a provider using a constant constructor initializer we're injecting the provider into it this in a nutshell is dependency injection in software development you could go into a lot more details about it but we don't have time for it um so what is a mock the mock goes very very well hand in hand with dependency injection in that in this case you can see we have an off service that is mirroring the functionality of its provider which you could inject into it but the provider that we're using at the moment is called firebase what if we created a completely new provider that we have complete control over we can we can make sure that it conforms and implements auth provider and we can make sure that it implements all those functionalities that is that auth provider implements and overrides all those but we have some special logic in our own mock auth provider then we will give this auth provider to our auth service and then let the auth service do its magic and and mirror all those functionalities of the provider so we're gonna mock an off provider and provide that into our auth service so that's what mocking is when you when you create a a new function or a class and then you can then inject that into another place and then test that another place okay so let's go in our off test dart file that we have right here i'm going to command s on it and let's go and create our little off like mock off provider so i'm gonna go in here and i'm just gonna say class mock off provider and suggest you do the same thing and this guy is gonna implement um the auth provider okay auto imported for us okay so like that all right now what we need to do is just to get mock-off provider to implement all the functionalities that the auth provider apps abstract class requires us to implement so i'm going to command dot on it and respectfully ask visual studio code to create those six missing overrides thank you so much visual studio code for making our lives easier okay now what we need to do is just to do the heavy lifting of this mock auth provider which means to go ahead and create the functionality for the auth provider okay i understand that the code is completely ginormous right now so i'm going to decrease the size a little bit so you see more of the code so let's go ahead and take care of the first function in here which is create user okay now you see what we're going to do is if you remember our auth provider has a function called initialize all right now when we're using auth provider in the context of firebase firebase internally has the concept of whether it is initialized or not but when we're creating a mock auth provider where is that functionality we don't keep track yet of whether our mock auth provider is actually initialized or not and we just have an initialize function but what if someone calls create user on our mock auth provider without having initialized the provider yet and that's what we need to do now so let's go ahead and keep track of that so what we're going to do here is we're just going to say var is initialized it is false to begin with okay and the reason i'm saying underscore is initialize is because um this is making this property pretty much private to our mock-off provider so we're indicating to the outside world that hey you shouldn't be reading from this property or writing to this property okay that is done now let's create a little getter for this property so that when we're testing our mock auth provider we can actually say hey are you initialized and we can also create a test for a mock auth provider which we're actually going to do is to say okay when we create the mock auth provider it shouldn't initially be initialized however after calling initialize on it then we make a test to make sure that initialize flag is set to true so let's in order to do that we need to be able to read this is initialize flag let's go ahead and create a boolean getter for it we call it is initialized it's initialized and we just return is initialized in there all right now let's go into our create user i'm going to put a comma at the end of that parameter i'm also going to take the liberty of going and creating and putting a comma at the end of login function and that's the only two places that had that required a comma at the end of their parameter list so now dart formatter is able to format the code a lot better okay let's go to create user now you see in create user i'm pretty much in all these functions that we're writing in here for instance login send email verification we're we need to make sure that this mock auth provider is already initialized so we're actually going to throw an exception if you call these functions that require initialization without having initialized the mock auth provider first so let's go and define a um an exception in here so let me see actually if i have written that down somewhere nope so let's go in here and just say class not mini initialized exception implements exception so you should know this from before and it's empty for now okay so what we need to do in here we need to just say if is initialized if it's not initialized then throw not initialized exception okay so that's an if statement it's a one-liner that's why we don't really break it in here otherwise you put curly brackets in here and then do the throwing in there but you could also use a one-liner if statement if that's all if that's what you're doing just one line of code all right and i kind of like these one-liner if statements to be honest with you so i hope you got this if the mock auth provider is not initialized throw that particular exception and what we're going to do is just we're going to fake creating a user okay so we're just going to say if you call the create user on firebase for instance it probably needs to go and talk with firebase back-end so it's going to take some time so let's build in some little uh delay in here and what we're going to do is just to say future and delete and here you have to pass the duration to it so we say const duration seconds and they do i believe that's it let's just say one in here and remember future delayed if i go and move over it's a function signature it returns a future of dynamic so by creating a future you're not actually waiting on it so let's mark our function as async and let's just wait on it okay now do then is to make sure that um this create user actually returns an author user but remember also in firebase um or i don't actually know if firebase works like this by but by creating a user what we're going to do in our mock auth provider is actually logging that user in as well okay so let's just say you see login returns also a future of auth user so at the end of this create user we're just going to make our lives easier and just return the result of logging in so let's just say return and log in when this email and password okay so this is a very dumb and very easy mock implementation of create user in itself it does three things checks to make sure that you're initialized and if you're not initialized it throws an exception it does a mock uh one second wait just to like fake making an api call and the third thing that it does is that it calls the login function with the same email and password and returns the result of login just so that it can get its off user okay now we need the mock current user so how do we do that how do we get a current user you see firebase has the ability to keep track of the current user but how do we do that we can't just go and delegate this functionality to firebase right now so we also need to create an auth user in here okay so let's go to deter mock auth provider right there off is initialized or below it doesn't matter somewhere i'm gonna do it above i'm gonna say user like this you see in far in a dart if you make a member variable optional by default it is null so it has no value so you don't have to actually go and say no and you can see it says don't explicitly initialize variables to no good good analyzer i don't have a user that we're internally going to manage and i'm actually going to make it prefix it with an underscore so that it is marked as a private function as a private member variable then in the current user simply return that user so like this okay perfect now we need to go and take care of the initialize function let's see if we can find it login here is initialize so the only thing we're going to do in initializers we're going to fake waiting just wait for like a second and and then set r is initialize flag to true so let's grab this code of a weight from our create user function and then bring it to initialize and then just say await and make your function asynchronous and then we're gonna just wait and we're just going to say initialized is true so that was an easy one all right so then the meatiest part of our mock author provider is actually the login function because it's not that it's doing login but it's also the function that the register function is using or do we say create user create user so that function is also logging the it's calling the login function so we need to really test this function to ensure that it's working properly okay as i mentioned before in most of these functions when we need to make sure that our mock auth providers initialize before these functions are called on them so let's go and grab this code you see it says if is initialized and bring that code as well in our login function so that's the first thing that we're gonna do now we're also going to build in some fake functionality into the login function just so we can write tests for them because you see in the real world you probably have like lots and lots of real logic that is inside your uh auth providers and auth services but we don't have all that real logic right now because our application is quite small right now so we're gonna build some fake functionality into our mod provider and then sorry in our mock auth provider and then we're going to write tests that test those scenarios so you learn about mocking and you'll also learn about writing tests for those mocks okay so that's the entire purpose of this chapter so what we're going to do then is we're going to say if and so we're going to make up an email that we don't like we're going to say if email is um fooatvar.com then throw user not found exception okay so if you're trying to log in with this email address we're just gonna say user not found okay and if password is foobar unlike the foobar password either then we're going to say throw wrong password off exception so remember login in itself if we go to our firebase auth provider so go to this file firebase auth provider dart it has those functionalities like if you have a look at login it has a functionality like handling user not found wrong password generic auth exception so what we're doing is that we're creating some sort of a mock of kind of the same thing but we're locking it to specific email and password okay okay so that's for password we don't like the email of foo at bar.com and we don't like the password of foobar now we're also going to remove the unimplemented error here now in this case let's just create a user so we're going to say user is and off user and it's email verified we just say true or let's just say false actually so we say when you're trying to log in we're just saying is email verify false okay now that we've created a user let's assign it to our user like this because remember we have a private field called underscore user and we just keep hold of it like this and then we will do because remember we need to return a future of that auth user then we say return future of a value equal to our user like this so that's our login function so that was quite a lot of work but i think you hopefully understand what we did right there now we have to look at a logout function and the logout function is gonna have some code as well so um it's not just gonna be saying okay i logged out as i mentioned before we need to make sure that the mock provider is initialized so let's bring that code in here boom okay and we also need to make sure if you want to log out that you've actually logged in before so let's just say if um if i can find my keys if user is null then throw uh user not found off exception okay otherwise what we're gonna do is we're just gonna await so let's find an await code from before we're just gonna fake waiting a little bit just one second okay and and we're gonna set our user as well to null we're just gonna say the current user then is not you can see it's complaining that we're using a weight but let me just say in here then async just like that then the error goes away because if you mark your logout function as async then you can wait on a future so easy as well logout says am i initialized and in order for me to log out there needs to be a user and then i'm gonna fake waiting one second and then i'm gonna set that user to null so easy pc okay now let's mock our email verification code so same thing so you should now be familiar with this let's just make sure that we are initialized i'm going to grab a code from there room throw unimplemented error actually let's leave it let's leave it there okay for now at least and um then during the send email verification what we're gonna do is you see when we did a login we said that uh let's have a look at the login we said by default the email for the user's email verification is false but upon send doing a send email verification we're just gonna flip that flag where all of a sudden i'm gonna say oh now outside of your email verified which which isn't so realistic but that's the logic that we're mocking right now okay and remember a an auth user uh here has a and it's email verified it's read only like you it's a constant you cannot change it so just because we have an optional user in our mock auth provider it doesn't mean that we can just go and say off user is email verified true we can't write to it so we need to rewrite this entire user okay so after checking that you're initialized what we're doing is saying that if let's get the user actually final user is this let's get your current user and we say if user is null and throw user not found so our send email verification code is make sure making sure that you've logged in before you can send an email verification or at least you register your user okay um okay then what we're going to do is to create a new user we're saying new user is an off user and his email verified is true this time and then we set that as our current user so we say the current user is the new user and then we just remove that and we make our sure our code async as well okay so that's for send email and verification so you see it did take a while but we've actually written now a mock auth provider that has its own code and it has its own initialization etc okay now what we need to do is to talk actually about tests so um let's see yes um so what are test groups and what are tests you see if you think of tests as or at least unit tests as pieces of code that test other pieces of code you may think okay i'm going to write a test for create user here i'm going to then write a test for current user i'm going to write test for initialized login blah blah now all of these are common and group they're kind of related they're all testing mock auth provider and that's what test groups are for in your test functions in flutter sorry in your tests and test suites in florida you can actually group your test functionalities into a group that has a name and then you can ask flutter to run that entire group of tests for you so that's what test groups are for so now what we need to do is to go into our main test function right there and basically create a group and then add provider inside that so let's just go ahead and then type group and in here we're just going to say mock authentication okay and let's go in here the second parameters as a function and like that so now you should have your code like this so basically you created a test group and you can see visual studio code is telling me that oh you can run this group so we're gonna put all our mock authentication tests inside this group okay and as a caption says the first thing we're gonna do is we're gonna create our an instance of our mock aus provider so let's go ahead and say a final provider is a mock-off provider just like that okay so now we have that so now we're getting to the juicy parts and i'm so happy about this because we've done quite a lot of groundwork just to get to this point for this chapter so now we're gonna write our first test so as you can see the title says testing provider is initialized providers shouldn't be initialized to begin with you see we're starting with a an assertion we're saying that according to our implementation the way we've implemented our mock auth provider it should not be initialized to start with so we're just making sure that by creating an instance of mock auth provider it's is initialized the boolean getter should return false if it if it returns true we're going to fail our tests so meaning that if someone then sneakily goes into the code later and says oh this is true by default then the tests are gonna fail and all the developers in the team are gonna be notified about that okay so let's create our first test the way to create tests in flutter is that you start typing test okay and you give it a name in this case i'm gonna say should not be initialized to begin with okay so that's the name then you're gonna provide it with a function to execute upon doing its test and in here you could say you could use a function called expect and you say writers provider is initialized it should be false to begin with all right so that's the first test that we wrote so test function then you write a name for it then a function to be executed and in there you can use various flavors of the expect function you'll see expect there are various flavors of that so right now we're just expecting the easy initialize flag to be false okay now the next test that we have to do um so as the captioning case test logging out before initialization the provider should throw and not initialize exception so basically what we're saying is that according to the log out function it shouldn't be able to log out if it's not initialized first so we're literally testing this line of code okay to make sure that no one just unintentionally comments it out or unintentionally removes the same we don't need it all right so let's test that uh functionality so let's just say test i'm going to look at my notes to see what i've named there cannot log out if not initialize okay now you know that as a second parameter to your test function you need to provide a function so uh parenthesis and then curly brackets and in here we're just gonna say expect and now we're using a new flavor of this expect and in here i'm just going to say provider log out and upon calling this logout function we actually want to expect an exception so there is a really good uh catch that you can use in here that is called throws a and you can see throws a is a matcher and it matches the result of the log out function against whatever you provide here so you say throws a and then you expect an exception in here you see the const type matcher height matcher is just going to say not initialized exception so i'm going to type this and then i'm going to show you what i'm doing basically in here see what i've done through jose const blah blah blah huh that looks fine as well and let's see why type manager is not extract method cons throws i probably messed up something in here yeah so let's see what is happening here so what we're telling expect in here is saying that execute the logout function and we're now testing the result of that function against something called a matcher and matcher is because you see in here you can't say that this result should be an exception because what are you going to do are you going to create a an instance of that exception that's not that's not a good way of testing your functionality in here you're saying you're matching the result of calling the logout function it gains that expected type as you can see type matcher is if you go into it you can see is a matcher okay so that's how you would expect a function to throw an exception all right all right a lot of information um now what we need to do after testing that functionality we just need to make sure that we can actually initialize our mock provider i'm going to bring the code a little bit up here so you can see it better so now let's go in here and say test and let me see it should be able to be initialized should be able to be initialized and create an empty function in here then what we're going to do is just to say await provider dot initialize like this and remember just like everywhere in your dart code you can make your functions asynchronous just by putting async right before the curly bracket so it's not a part of the signature of the function it's just telling dart that inside this function i'm going to execute some code asynchronously okay so upon initializing we then after initialize if you look at the code that we did for initialize it just does a uh and a weight of one second and then it sets the flag of is initialized to true and we can read that flag by reading this boolean getter so let's say away provider initialize and then we're going to say expect the provider is initialized flag to be true after this all right so that one was an easy one so after we've done all of this you see is initialized and doing initialization is not actually going to create a user for us so let's make sure upon initializing our provider that the user is no so let's just say test user should be null after initialization okay empty function and then let's just expect the user the current user to be known so let's say expect a provider current user that it should be known all right so easy to read and it's almost like reading english so so that's it all right now what we're going to do is doing some asynchronous testing i want you to see this as well because it's very important now let's say that you're we want to test as the caption is telling you testing the time required to initialize we can test timeouts in this case so what we're going to do is look at our initialization code here and let's see the initialize function here at the moment is waiting one second what we're going to do in our test just for the sake of using how you can test timeouts and how you you can test for instance api calls in the future we're going to do some asynchronous testing in here with a timeout saying that our test should fail if initialize on our provider takes more than x amount of seconds all right so now let's go in here and say test um should be able to initialize in less than two seconds okay and an empty function which is asynchronous just like that empty body for now and what we're going to do in here is to say await on the provider's initialization okay and after initialization we're also going to expect the is initialize flag to be true just like that however we're going to use a new parameter of our test called timeout now timeout will provide a constant timeout to it with a duration so duration and in this case we're just going to say two seconds and i think we have one extra parameter in here constitution timeout argument zero expected what one found cons time and then here seconds and avoid cons here okay so this is very simple simply said we're saying that we're created a test that calls the initialize function on our provider and just ensures that that function returns to the test context before the timeout has passed so internally this test function which you provided timeout to is going to create a little timer and then it's going to set the timer to start with as soon as it calls the function this function in here let me show you here this as that is progressing and doing its work it's going to terminate its result processing as soon as the timeout basically passes so in this case our initialize function is going to take one second to process this work if it can't do that during these two seconds of timeout that test is going to fail okay so now you know how to test that as well so let's go in here and now test the medius part of our provider which is creating a user as you can see we have to test make sure that creating a user actually delegates to our login function and we have to test all the edge cases all right so let's go ahead and do that let's then say we test uh create user should delegate um delegate to login function and in here we're gonna create a function which is an asynchronous function all and what right need to do is to create this basically if you remember create user doesn't have internal logic of its own it's just going to call login but login has this beautiful logic that first test fooadbar.com with any password should throw this error user not found off exception so let's just test that scenario okay let's go in here and say final bad email user is provider create uh writer oh don't we have our provider oh i've added this test i apologize i've added this test i believe at the end of this entire test group i should have added it here so if you've made the same mistake i apologize for that it's my fault you should fix that and make make sure that your test is in the same group where it has access to the provider so then i'm going to say provider and so final bad email user is uh provider creates user the email is fooatbar.com and password could just be any password okay comma semicolon make sure dart formatter formats your code properly so then what we need to make sure is when the bad user is basically returned to us then it should actually contain a user not found off exception so let's go ahead and say expect a bad email user to actually be of to throw a const type matcher of that user not found off exception like this okay let's see and i have to close that here as well so we're basically saying calling the bad email user the creation of a user with that specific email should throw a user not found off exception and remember you may think oh we've tested this before yet but that was in the context of here let's see actually no we haven't tested that before it's it's this thing that we've tested so sorry about that so we've tested a lot yeah we haven't tested this particular case so all right so now we've tested that now let's test this scenario with a bad password a password of fubar you see we have that logic in our mock provider here for the login function let's test this scenario now let's test this code we should throw the wrong password off exception okay so let's go in here and say final i can see that you can't see the code so bad password user is provider and create user with the email of let's just say someone at bar.com and the password is fubar and that's the password we didn't like remember that okay now we copy the code from here and then we say that that password user should throw an exception called wrong password off exception okay so we've tested that scenario as well now we actually should test the um the positive scenario so let's go ahead and say final user is awaits provider and we say create user all right an email is going to be foo and the password is going to be bar remember our our mock auth provider is not actually testing whether an email is correct email or not firebase is doing that but a mock provider isn't doing that so we could just provide any email foo and password a bar and it will just accept it as long as it's not it the password isn't foobar and as long as the email is not footbar.com okay all right now let's let's make sure that this user is then being assigned to the current user of our auth provider okay so let's expect the auth provider offer sorry the provider's current user to actually be equal to this user okay because um that's what we did in our create user remember we create user delegates this work to the login and then login internally sets the current user to that user they just created okay so that's the scenario now we're testing with this line of code here all right so that's that um so what we need to do then is just to make sure by just creating a user which we're doing here that the is email verified functionality sorry that is email verified um parameter of our auth user is set to false by default remember login function here is set is email verified false let's test that functionality okay so we just say expect users we use email verified to be false right wow that was a lot of code to be honest with you and i hope that you got everything that i mentioned here so now that we've done that let's test the email verification functionality uh and let's have a look at what we actually did in email verification you see we have this functionality not initialized then we take the current user if the current user is null then we say user not found exception and then we create a new user with is email verified to true and we're then setting that user as the current user so that's what the send email verification code is doing okay now you see when when flutter then runs our code it's going to run them sequentially so it's just going to go from top to bottom and then you remember before we test the email verification we're actually testing create user which in turn calls the login function so since we're keeping a hold of our provider this create user calling login function ensures that the current user actually sets and is not email verified so we can count on that okay so let's say that we test and we say login user should be able to get verified uh logged in user should be be able to get verified okay and then an empty function in here um like that so in here we then say provider send email verification okay and with the final user is providers user uh current user like that and we now make sure that the current user is not null so we say expect user is not uh or yeah expect the user is not null which as you can see is a great matcher that you can match something against it so you say shouldn't be no okay like that all right and then we also we need to make sure that this user's uh verification is set so it's email verified should be true then we say expect and we'll get an error now you'll see user is email verified it should be true okay and you can see you get an error here saying that a user is optional but we're gonna and do an asterisk here saying that force force on rapid for us okay now what we should do as the last test we as the caption says test logging out and logging in and this is normal scenario that should just work let's create a test for it so let's just say test and we're going to call it should be able to log out and log in again should be able to log out and log in and again okay and an async function so and a semicolon at the end so what we're going to do here then is just to say log out and log in and then we get the current user and we just make sure that you're not null so let's say a wait on the provider to log out and we say await on the provider to log in with an email of just user and password just like that okay so or just email because we're not actually validating the email and password in our auth provider in our mock author provider and then we're going to get the current user so we say final user is provider current user and we just make sure that that user is not known so let's just say expect the user is not null which is a method built into flutter tests all right that was a lot of work and i'm proud of you for sticking with this chapter we talked a lot about tests there's so much that you need to go through so much material and you need to learn on your own as well about different types of matters and different flavors of expect and talking about expect i kind of expect you to go and read these things also on your own and learn about them in your own time as well now the exciting part we need to run our tests so let me change the screen layout and let's go in our terminal here and let's increase the size and let's then uh break this and as you can see you can tell flutter to run your test by saying flutter test and providing that path to your test so now flutter is going to go ahead and issue and go through those tests one by one and let's see what we get as the result and you can see it's giving like time for all of these tests and it says all tests passed now i just want to highlight this before we go on we did a lot of tests i've prepared these tests manually so to make sure that they actually testing important functionality inside our auth provider however i've written the tests very carefully to make sure that they work this is not the case when you're doing things in real life your tests should fail if you've done things right your tests should fail to begin with and you then need to go and write your and fix your logic if you're doing things even more right you should write your tests first nothing is going to work then you should go and write your logic to fit those tests and expectations so just because these tests are passing right now i know we have joy inside we say oh everything's passing everything's great but in reality that's not going to be the case usually okay so a lot of work we did let's do as we usually do keep the tradition and let's commit our work and and also tag it so let's then say git status to see the status lots of things changed hey hit add git status all right we're going to commit this as step 10 and we're going to say in here get push it's going to push our commit to github and then we get the tag as well as step 10 and push tax traditions as it is tradition in this uh philosophy course we always talk about what we're going to do in the next chapter before we wrap up the current chapter so as you can see the cache has said let's get ready for the next chapter we need a database to store user notes before you use or if we use firebase for storage now you see we at the moment we're not actually writing anything anywhere there are no nodes uh the user can't even create new nodes so but what if we wanted to give the ability for the user to create new nodes and then delete those nodes and update those nodes and uh to begin with uh we're going to store these nodes in a local database inside the application so you will learn in the next chapter about sqlite and local databases and how to use them with firebase sorry and how to use them in flutter in the latest chapters in the later chapters we will change that logic so we'll be won't use sql lite uh but i believe for any developer uh if you're like a i can't say any developer but if you're a front-end developer or a back-end developer you should be comfortable with databases and that's exactly what we're going to do in the next chapter so grab some refreshments and i'll see you in the next chapter hello and welcome to chapter 27 of this flasa course in the previous chapters we've been talking about our user interface and also we've been looking at our um services and we've put some time also to create some um tests for our services and providers up until this up until this point we've been talking quite a lot about like the logic of going from one screen to the other uh integrating with firebase etc however we haven't actually talked about storing um user created content inside our application or inside some sort of cloud service what we're going to do in this chapter is we're going to talk about sql lite and storing user generated content in this case the user generated nodes inside sqlite now i'm gonna get to what sqlite is but first of all let's have a look at the title of this chapter which as you can see it says crotlocal storage for those of you who are software developers from before and are comfortable with crowd you can just jump over this part of the chapter for those who are not familiar with crowdcrot stands for create read update and delete these are four very fundamental operations that any developer would perform on their data and for instance if you're a flask or a django developer node express um developer you're you're probably already familiar with these because you're probably using some sort of a database mysql or sqlite um and you're storing your data in there and you're just working with the data and you're familiar with the term crop but if you're not familiar with it then think of it as c which is create is you creating some sort of a an object inside a database some such as for instance a user generated note you read of course want to be able to read that data back for instance in our application's main user interface you may want to read the entire contents of the database not the entire contents but at least in user generated notes for that specific user so that's the r in crowd then you have u which is for which it stands for update um or it doesn't stand for update it means update because u is the first letter of update so on update is for instance if i have already generated a node inside this application i want to go and change the contents of that node then that's the u in crod and um last but not least you have d which is delete um and as its name stands basically you you allow the user to be able to delete their own generated content from the database so what we're going to do in this course is to um talk about sqlite that is a database or a c library and a library created in c um that allows us to see as a programmer language c that allows us to store data inside a file now if you're if you're coming from like the backend world if you're if you're programmed with inside with python in django you're already familiar with this because sqlite is the default database that will be provided to you in django and a flask as well i believe is using sqlite by default which is very similar to django but if you're not familiar with sqlite is i've prepared a website here which i mean i haven't prepared the website i've just opened the website so um so you can see here i'll increase the size of the font here and you can see sqlite is a c language library that implements a small fast self-contained high reliable full-featured sql database engine sqlite is the most used database engine in the world well just think of sqlite as the database engine that we're going to use in our application and it's not something that is built in inside um flutter we will have to use a so-called plug-in for it um but that's also okay and i mean not many languages have support for talking with a database and natively so um but we'll get there we'll get to that point okay now let's talk about how we're actually going to integrate with sqlite and to start with so i'm assuming that you don't you have never worked with sqlite before or you haven't worked with any type of database before and you're trying to learn how to do that okay so that's that's been my assumption from the beginning of this course so if you're already seasoned developer you know exactly how school sql light works you may want to jump over this section of this chapter and get to like more juicy parts where we integrate actually with equal light inside the floater application so let me close this um or maybe let's just keep it open and what i'm going to talk about now is um a program a free program called db browser for sql lite you see sqlite allows you to i mean if you think of sql lite has different components first you have your database which is just a file that sits on a disk and then you will have the sqlite engine that can read from this this file and write to this file so that's the engine and then this engine should run somewhere so it's either going to run inside an application such as the one i'm mentioning here a db browser for sql light okay so sqlite's like baked into that application or you can also bring sql light into your terminal so that you can actually talk with sql lite databases from within your terminal or if you for instance have install django on your computer then you can use django in order to integrate with sql iso sqlite is the engine that talks to the sqlite files uh which are your databases but then it this engine should run somewhere it's not just an executable that like you say here take this file you now have to have like some sort of a container where the sequel light engine basically resides when we then talk about our flutter application we're going to bring this engine into the flutter application so our app can talk with that database but for now we're going to look at a program called db browser for lite db browser for sql lite is a free and i believe it's an open source program let's search for it i'm going to say db browser for sqlite and we end up in this website and um and as you can see the official home of the db browser for sqlite and this is how the program kind of looks like um i'm not sure if yeah i can see now it's actually available for windows mac os and it would be amazing if it was available for linux as well um yeah so it seems to be available uh and you can actually use snap so that's great so if you're on ubuntu like i am not on this machine right now but if you're on ubuntu you can actually use snapstore or even debian any type of operating system linux space operating system that has snapstore so that is really good even on arch linux fantastic all right on debian you used apt so that's fine but anyway so it's available for windows linux and mac os so i need you to basically go to sqlite browser or db browser as it's called db browser for sqlite if you go to the home page i need to find this website and let me change the screen layout so you see it better and i need you to download this program okay i've already downloaded it on my computer so i'm going to close that safari window and i'm going to bring you the db browser for sqlite as it looks like on my computer the only thing i've changed on my interface here is i've changed the font from 13 to 20 not because i don't like the number 13. it has nothing to do with that but it's just i thought 20 is a little bit of a nicer font size for this course um all right so what are we gonna do now so um let me then talk about the structure of our database and how we're going to set it up if you think about how we've created our user interface in that here's the user interface if we go here you can see that we can register with different users so then we have a user entity or a user table as we're going to call it and then we also have we are going to allow the creation of these users in our database so imagine that we will have some sort of a table some sort of entity in our database that is dedicated to users and users are probably just going to have a what are they going to have they're going to have an id and an email so as you remember when you create a when you register a user with firebase you always get a user identifier so we're gonna store that id plus the user's email in our database okay so we're not gonna store the user's password that isn't that is an absolute no-no okay so user id which comes from firebase and the email address we're gonna store in our database and also we are going to have another table and another table in our database dedicated to notes so as a user when i log into the application i should be able to create my own notes and these notes should be kind of like bound to and like they should be glued to my user so if my user is in the database i should be able to have notes and if my user is deleted all those notes should kind of also be deleted from the database so it's kind of like a cascade for those of you who are familiar with back-end development so that is like the structure that we're going to set up for our database so in our i can see in my notes that for our notes table we are actually going to have a user id integer in that table that like binds the every node object to the user who created it but we'll get there so don't worry about it so i'm going to get rid of this here and put it there so we don't see it now what we need to do is start testing so we want to create a database a simple database and start creating some tables in there okay so what i need you to do is just to press the new database and i'm going to save it on my desktop and let's just call it testing okay and i'm going to press the save button right there okay you can see now we created a database and we have a table here it doesn't look so nice i mean it's not rendered so fine because i've changed the font on my screen but you i think you can you get the idea okay so what we need to do is to as the caption says we need to create a table called user okay so go in here at the table section here and i'm improvising a little bit here because this is like something that i plan to show you but i haven't actually prepared any notes for it so let's just go ahead and create a table here called user and as you can see we're gonna be able to have some um fields in here what is called a field in here is pretty much just like a column so by creating a field you're creating a column okay and the great thing about db browser for sqlite is that you can see the sql code that will be generated for you which we're actually going to use later when we integrate sqlite into our flutter application but for now i just want you to get the idea of how sqlite works how it creates the tables et cetera okay so now we have the user uh empty table it doesn't have any fields or columns i need you to press this add button right here and what we're going to do is we're going to just create um an id field now if you're not a developer or software engineer friend before you may not know about id field and why it's important or if you're a developer from before you may know id as primary key from before so um an id is just usually an integer identifier an integer is a number so a number identifier for every row that you later later insert into your table so why is it important because usually an id is something called a primary key and a primary key by default is is unique what that means is that for you to be able to create a user in this table it has to have its unique identifier now if you remember how our um how we are basically treating users in our user interface is that we're treating them by their email so you may think well the email is a unique thing as well so why don't we go with uniqueness off the email well we can apply uniqueness constraints on the email field and or the email column but it is very well established pattern in database um world where you're working with databases that you i mean you can make a string column unique such as then such as an email but a primary key is usually an integer such as pk or id so it's just a convention and it's also a good practice to not go with like a uniqueness of a string because it takes more resources in order to calculate the uniqueness of a string than it takes for an integer so we're then going to call this field id going to be integer and there are some fields in here which are not rendered so well i'm going to increase the size of this and i'm going to do like this okay so what we're going to do in here um we're going to take you see n n in here at the type we're going to leave as integer that's fine n n means not null meaning that this field should always be present it should never allow the value and emptiness of the value or the absence of a value to be present there okay the absence of value to be present i hope that makes sense basically just means that the value cannot not be either so we're we're going to leave it like that pk stands for primary key and that is what i oh actually i can move my mouse over them that's great primary key so um it means that it is the key using which is a unique key in this table using which we should be able to then easily query different users from this table so what we're going to do is we're going to take this item right here okay ai is auto increment i believe and auto increment is a great functionality in sqlite and many other uh databases that allows you as the as the name uh suggests and as the name indicates that by you creating for instance a user with a specific email and you insert that user into the database in this table and you don't even have to assign an id to that user you just say here is the user email boof put it in the database then excuse me then sqlite is smart enough to say oh i but i need an id field as well you haven't provided it and then it looks at this field and says oh id is auto increment so it's going to create that id for you and increment the previously generated id and assign the new id to your object for instance if you have no objects inside this table and then you add a new user then it automatically gets the id of zero and then if you generate the next user and put it in there then it will get the id of one so you get the idea okay and that is exactly what we're gonna do for this particular field and unique is just yeah as its name indicates this field needs to be unique but if you indicate something as primary key implicitly it is a unique field okay and to be honest with you we could actually check not null as well meaning that yeah it should always be there so just in case so that's for the user field okay sorry it's for the id field and now let's go ahead and create a new field for the user's email like this and for the email you should say that it is a text okay and what we'll do we'll say it shouldn't be null and also the emails are unique so have a look at this now it generated code for it that says create table user id integer not null email text not now unique and it sets a primary key of id with an auto auto increment so this is kind of like the code that we're actually going to use in our flutter application in order to programmatically create this table later but for now just keep it in mind this is kind of like the syntax of creating a sqlite table programmatically okay all right so then you can press ok in here and now you can see the user table has been created for you and here's the code for it or the schema as it says right there all right great stuff now as we did the user table we need to go and create our notes table because remember from before i said we're going to allow the user to create notes when they're logged into the application and by the time they're actually logged into the application we should have already created a user uh row for them in the user table and then by creation of every note we're going to create also a new note in the database in our note table which we're just going to create as the caption indicates and then we're going to bind that note to that user in the database so i need you to go here then and then we need to create a new table by pressing create table button okay so as the caption in the case here let's call this new table note and we're then gonna start by creating a new field called id and we've already gone through this you know exactly what to do in here an id field as integer and we say it shouldn't be in it shouldn't be null it should be primary key and and i think that's it to be honest with you so not null and auto increment as well of course so all right so that's for that's for the id of a note now what other fields do we need in here so what we could say is for instance that you have a a user id and so you want to bind a user to a node and what we're gonna do in here we're gonna bind this we're gonna say literally that this oops where did it go oh it's a little bit strange interfacing here so that's okay too um so user id integer and we're going to say it's not null and also what we're going to do is to what we want to do is for this user id to be kind of like bound to a user tables id field and that's that's called a foreign key so you have a primary key which is the key that your table itself manages as its own field and then you'll have a foreign key as its name indicates that it is it is a field inside your table that is bound to another tables something else column so in this case our user id should be bound to the user tables id column and you can create that with db browser for sqlite inside constraints and in here let's see we add a constraint and we say we have a foreign key and in here so let's say sqlite foreign key and we say the user id and we say apply and you can see now it says foreign keys or id references it's not at the moment referencing anything so i wonder if that field is hidden somewhere to the right hand side and how we could possibly create that let's see i just remember from before that this was a little bit strange to get working from the beginning so name oh maybe it's it's the name right there so so let's say user id references sqlite foreign key let's see how it's created foreign key user id references let's just say name should we say um in here if i say blob what happens foreign keys ready references contains blah so that's not that's not really what i wanted in there so i'm going to remove this plot that i just created and let's see if we can change the sequel we can't are there no other fields available here that we can play with perhaps not and i want to remove this just to see if i've made any mistakes in there so let's say so here i can see we have a user id and then there is a foreign key and i can see here this is perhaps the right actual way of doing i remember there was something really strange about it and now i remember that it is hidden under this foreign key um column unfortunately i believe it's a little bit of a strange interface that's okay i'm just still very very grateful that we have db browser for sqlite as a free software and perhaps even an open source software i'm not sure about that and i'm very grateful for every developer who's worked on this so i just hope that it um that's understood but what we're going to do here in here we want to bind this user id to the id field of the user table so just click here under foreign key and double click actually i can see then this magic thing appears here so let's go ahead and say that we want to bind this to the user table id field and i believe that should be it yeah and you can see now the code generated here says we have a foreign key called user id and it references the user table id field okay perfect um now we also need to do is to create another field in here and that's the text of every note so what we're going to do for notes is going to be very simple our notes are not going to include any sort of um they're not going to include any sort of for instance um images they're not going to include any sort of ordered list or unordered list they're going to be simple texts okay and they don't even have titles the title of a note we're going to derive from the text of the notes so it's very simple so for the text of the note let's just go say it is of type text and uh i believe i believe that's all we need right now so user id text and yeah that's fine and also to be honest with you if you want to you could also create a other fields in here you see in this uh in this course what i what i want to do in the beginning is to allow us to create a local database that you can store all the users notes in it but i want you to also be able to later in the future get rid of this local database and replace it with firebase that's like the goal um however some of you may actually decide to keep this local database store the user's information in this local database and not the user's information the user's notes in this database and then you may want to decide to have some sort of a um utility service that sits in the background and syncs these notes with firebase at appropriate time so that's up to you if you want to do that then you may want to actually create a little fill in here that's called is synced with server or something like this okay or it's synced with cloud i've called it in my note so let's go ahead and do that although we're not actually going to use this field but i just want to demonstrate to you that this field is possible to achieve with sqlite then in here let's say it is an integer also um and we're going to say the default is 0 meaning it's not synced basically true or false in true could be translated to any value that is not 0 and 0 could be translated to the value of false so putting the value of zero in here meaning that it is not synced with any cloud storage so let's then go ahead and say that uh this is integer and it's um we should say it's not null and um and it doesn't have to be unique so now you can see that this is the result of the creation of our tables this is id integer not null and the id is also primary key in auto increment then there is a user id which is integer not null but it's also a foreign key to the user table under the id column or the id field and then we have another field here says text of type text and then another field that's called isync with cloud integer not null default zero okay so that's all we need to do and i'm going to press okay and i need to do the same thing on your side all right now we have two um we have two tables in our database so let's go ahead and um let's go ahead and move on to the next point that we're going to talk about you see as the captioning case we need to create these programmatically otherwise we have to move this database that we just created called testingdb manually into the documents folder of an application i'm going to explain what this actually means you see now we have a file called testingdb it has the database for our application with some tables okay however we need to be able to create these tables programmatically if they don't exist inside our application you see this testing db for me is sitting on my desktop it has absolutely nothing to do with our flutter application and you could be smart and like drag this db into your firebase application flutter application and then kind of copy it to the right place when the application is is executed in the user's telephone or on the tablet and then try to read from that database it is possible but what i'm going to do in here is i'm going to show you a better way of doing this in that we're going to actually create these tables programmatically in our flutter applications so that you also see that process and how that works how can you integrate with sqlite inside your flutter application okay all right so in order to do that as a captioning case we need a few dependencies uh we need sql sqflight path provider and path and um i'm gonna then explain to you why we need these dependencies you see sql sqflight is a package it's a third-party package that we need to add to our application in order for our flutter application to be able to talk with sql flight so that's that's that and that is for storage actual storage and talking with the database that package used for okay now there is a dependency that we have to drag into our application called path and path is used for us to be able to grab the applications documents folder so that we can actually create a file inside a documents folder and place our data inside that file just like i'm placing the data for nodes and user inside this testing db file on my desktop so the path uh provider and the path provider uh i may have actually taught set paths but it's actually called path provider path provider dependency allows us to grab the the applications documents folder and if you're not familiar with mobile application development you may not know this but applications that sit on the uh on an android phone or tablet and on ios telephone or ipad os tablet they have their own file structure so every application in itself has a document directory so whereas on your computer like if you're sitting on a from a laptop or a desktop you have a documents folder that other applications that run on your operating system could get access to so it's one documents folder every application can request access to and store information in it and read from it but that's not the same concept in mobile devices and on tablets in that every application runs inside something called sandbox the sandbox is like a it's like a cage inside where the application resides and all the application data resides in that sandbox so every application can request access from the operating system to read its own documents folder okay and that is what the path provider package is gonna allow us to do to find our applications documents folder in which we're gonna store our database file now we also need as i mentioned a a package called path and we need this path just for a very single up a simple operation and let's say that we have uh use path provider to get our documents folder now we want to create a file in this documents folder and kind of like get the full path of this file documents folder slash this file and that's what we need the path package because it has a great function called join that allows us to take the path or of a directory or folder and join that path with a file name and it gives us the entire path back so we can access that file okay so a lot of information i'm gonna take this um into another screen so you don't see it and i can see here it's asking for to control this computer's access now i'm going to deny that for now um all right so what we're going to do i'm going to bring our code up if i can find it and here's the code how we left it in the previous chapters and i can see that it is running excuse me in scrcpy i'm going to bring it here i'm not actually sure if you need a crcpy in this chapter so it may be better for me to just to minimize scr cpy and i'm going to make this code a little bit bigger here as well okay so so what we need now is to first before we go ahead and actually create our notes service is to bring in those dependencies okay let me change this screen layout a little bit so you see better i'm going to increase the font as well so i need you to go to your uh editor text editor or id if you're using and we need to bring in those uh dependencies okay so let's go and bring up uh your web browser and say pop.dev and in public dev search for sql flights okay and you can see it's right there and the way to install it is very simple you should be able to just say uh flutter pop at sqflight so let's go ahead and do that by hand and let's give it a flight remember it's not sq sqlite it's sqlite okay that dependency has been added then i'm going to say flutter pop add provide a path provider and we can actually search for it in popdev path provider and it is right there it's developed by the people who have brought us flutter and so to begin with at google so it's not really a third party application or third party uh package and we can actually have a look at sql flight as well and see who's developed that oh it's another yeah it's another publisher is not flutter themselves so let's go back to path provider and i'm gonna just say installing as we can see is flutter pop add path provider let me just copy that and paste it there add path provider and then we also need path so let's go back in here and just type path i believe this is my flutter team yeah dark dev so let's just say flutter pop add a path alright that's going to do its work and now if you go to our um pop special then you should be able to see those uh dependencies sqflight path provider and path are right there okay now that we've done that we can go and do what we uh are supposed to do in here which is create our notes service you can see that in the uh in the description i've provided here in the caption i said that we're in creating inside a folder called crud and we already have lib services you can see in here lib services and lib services auth but we don't have crud so i'm gonna go in here in lib and just say new file and i'm gonna say services well slash absolutely it's saying that it already exists so inside services i'm going to say new file then i'm going to bring it so you can see it as well oh where did it go services new file crud i think i need to change the screen layout so unfortunately so you'll see it better services again new file in here a new file uh third time or fourth time lucky crud and then nodes service dot okay so what we're going to do with this node service is to uh is to basically grab a hold of our database it is the primary service that is gonna work with our sqlite database it's gonna grab users it's gonna create new users delete users it's gonna find users it's gonna create notes delete nodes update nodes everything everything that we need from our user interface this node service is going to facilitate that for us okay okay so what we need to do inside uh are so what we need to do now is to actually i think before we do that we need to import our dependencies so let's import our dependencies we need uh three dependencies if you remember path path provider and sqlite so um i'm gonna bring those in here so we don't have to type it again so imports are kind of like boring and i i don't rather not type them so let's go in here and you can have a look at what i've imported here package sql flight and then we import that then we also have the path provider okay so that we can get the documents folder for this application and then we also are importing package path path and then i'm doing this show syntax in order to bring in this particular function called join all right so you could also skip that but the problem is that then you get everything inside path of dart and that's not what i want so i just want us to get this particular function inside path.dart and you could also do the same thing in here to be honest with you you could just say show um and i think the function is called get application documents directory so let's do that why not let's just get that particular function from path provider as well okay we don't need the entire path provider all right all right that's great so what we need then is for us to be able to grab a hold of our current database path as i mentioned are every application that you develop with flutter for mobile application mobile devices such as android and ios and ipad os they have their own documents directory and we're going to create and we're going to get the path of the documents directory and then we're what we're going to say is we're going to join that using path dependency with a name that we are going to specify for our database okay so um what we need to do then is to let's go ahead first actually and take care of some other important matters that uh need to be dealt with before we actually create the function functionality for for our database uh implementation you see note service is going to talk with database but before you can do that it needs to have some sort of dart representation of those two two very important tables that we created um user and note so if you read that data from the database how are we going to represent it inside our dart application and for that we need dart classes so what we need now is to as a caption in the case we need database users create a class called database user inside notes service dart all right that is going to be a bit of code so i hope you're ready for it and let's just go ahead i'm looking at my notes let's go ahead and create as the caption indicates we create a class in here i make the a little bit bigger class and i'm just going to say database user okay now if you remember from db browser for sqlite i'm going to bring it here every user had can we actually oh we can browse it but i want to go back to the user and modify the table save it and you remember it had an id and an email id was integer and email was text so that's what we're going to define in here okay so we're going to say final and id and final string email get help from visual studio to completely complete this i'm not going to explain these again and again because we've explained this quite a lot in previous chapters so by this point i just assume that you know what these are let's make this a constant initializer and then let's go ahead and say these two parameters are required parameters so they become also named parameters by default okay and that's that put a comma here so we get dark formatter to do its magic and what we're going to do is remember when we actually you shouldn't remember because you don't know this maybe yet but when we talk with our database we are going to read like hash tables for every row that we read from our for from that table so every user inside that database table called user is going to be represented by this object a map of a string and an optional object okay so that's a row inside the user table now imagining that the this node service that we're going to create soon reads these users from the database and it should be able to pass this to our database user class and the database user class should create an instance of itself depending on the values inside this map all right so let's go ahead and create a constructor we call it database user and then we say front row and then we say we get a map of a string and an optional object in here and then let's just call it map okay so what we're going to do in here is we're going to create the shorthand for creating and constructing our object and we'll say the id is equal to inside this map there needs to be some sort of a column called an id column so instead of hard coding that in here like this let's go and define a constant here and just call it id column and let's just say that this is equal to id and in here we're just going to say id is equal to ib column just like that all right and then what we're going to say is we also need the email an email is equal to map and remember we have the email i'm going to open the user in here modify table and let's go and have a look at this email which is text right there okay so the table that column basically is called email so let's go and go ahead and create const i'm going to make this a single single code as well because that's like the preferred way of doing it and let's call it email column and i'm going to assign this to full email and in here i'm just going to say email column as a string and this should be as inked so this was i mean it looks complicated but it really isn't so and you can see it's a constant so we could also actually tag this as immutable and we need to import foundation in order to be able to do that okay now that we have our database user we need to also implement a few more functionalities for this class before we're actually done with it so the three things that we need to do for it is first to create like a string descriptor for this class so that if we're printing out this user to the debug console otherwise i mean before i say otherwise if we're printing out an instance of the database user to the debug console so we're looking at the various users that are inside our database if we do not implement two string on our class it's literally just gonna say instance of database user in the console and that's not so useful so it's my it's my um habit to if i'm planning to print out these things to the console it's my habit to go and implement two strings so let's just in here say to string and it gives us the overwrite and what we're going to do in here is just we're going to say a person and person id is equal to dollar id and email is equal to dollar email okay so that's for your to string then what we need to do is also implement some sort of equality behavior for our class you see we want to be able to see if two different peoples that we've retrieved from the database are equal to each other or not so if if i say if person x is equal to person y then like read the person wise notes such as something like that so let's go and implement equality for our class and the way to do that is you overwrite a boolean operator and it's called bool operator equal equal and in here you would have a covariant which we haven't talked about yet and i will talk talk to you right now about it so what covariance is is a keyword in dart that not many people know about but it allows you to change the behavior of your input parameters so that they do not necessarily conform to the signature of that parameter in the super class so remember we're doing overwrite here meaning that there this functionality this operator is already defined at the object level so let's go to object just type object somewhere for instance void hello and then say object and then command click on it just so you can go there and search for operator equal equal and you'll see in here that it says external operator equally and the parameter should be of type object now we don't want to do that we want our classes to be compared to other classes of the same type so if you don't put covariant in here you'll get an error from the analyzer and you'll soon see that actually we're going to remove that soon so in here we're saying that we're going to compare our class with equal equal and instance of our class with equal equal and we're going to compare with another user of the same class okay and then here we're just going to say our id should be equal to the other id that's our equality now let's go ahead then and remove this covariant as i promised you and now you'll see you'll get an error saying that oh wait a minute according to object equal equals should compare the current object with another object but using covariant you're telling dart that hey i'm not comparable with other objects of any other class i'll only comparable with database user instances so make that happen all right so then after you implement equal you have to also implement hashcode as is suggested by the analyzer so i'm going to get help from the dart from visual studio code and i'm going to say create method hashcode and in the overwriting of hashcode i'm just going to return my id's hashcode okay so this basically the id is becoming the primary key of this class using which it will hash itself so it can be placed inside maps or hash nodes if you're if you're a ros developer or a dictionary if you're a swift developer so uh that's hashing okay so it feels like we're actually done now with this um with the with our database user so and that was quite a bit of code but we managed that all right now that we've done the database user we need to do something similar but this time we need to do it for our nodes so we have a database user now we have to create something called a database node okay note not node and i'm going to do that under the database user just so that we can have closer access to these constants all right so i suggest you do the same thing so let's just say we create a class and we call it database note and remember from our database schema that a note so if i go in here and say right clicks right click and modify table then we had id user id text and a field call is synced with cloud all right so let's go ahead and do that id is integer user ids integer text is text or string as ins is synced with cloud it's just an integer in here but we're gonna represent it as a boolean all right so keep those four fields in mind so let's go ahead and say final id and mint id and we have a final int in our database we call the user underscore id because that's a convention in sqlite or sql generally that you don't put you like you don't write your fields with user uh id usually you don't type like this the way we type with camel case in dart in other languages we just say user everything's under everything is lowercase and different words are separated from each other with underscore but that's not the case in dart and other languages instead we say user user id like this with panel case all right and we're also going to create let me just move this a little bit there and we're also going to create um the string for our text and last we're going to say is synced with cloud something like that all right and again remember we're not going to use this input cloud it's just for you to understand how we create different fields in the database and yeah it's just it's just something that you future you guard yourself against future changes in your database schema so by doing this you're allowing yourself to play with this field so that you know every note that is locally created in the local database is not by default sync with the cloud all right i want to get help from visual studio code to complete the constructor for this and i'm going to go and do all of these fields as required so i'm going to say required and i'm going to copy that paste it right there paste it right there and there and then i'm going to put a comma at the end and command s on mac or control s in windows and linux to save this and get dart formatter to format this file for me all right so that's the initializer and we kind of also need to do the same thing that we did here for our database user and that we need to instantiate it from a row so let me copy this code the way it is right there and i'm going to bring it into our database note i'm going to paste it right there and instead i'm going to say this from row initializer creates a database note in our database note we have an id but we don't have email so in here we're just going to say user id is map then we need a new column which is called user id column okay so let me just see my notes how i created it yes i can see it's called just user id call so go ahead and create a new constant in here and call it user id column which is if you remember from our schema it was called user underscore id so user id okay and here we say user id is equal to map user id column as a string and it's complaining right now because we have two more fields to initialize but we haven't really read their values from the map so text and is synced with cloud so for text we're just going to say text is equal to map and let's go create a new consonant in here we say text column and that's equal to text so it's just the name of the field or the column here you see so let's go ahead and say that's text and in here we say text column and we say add string and i believe that's how we call it yeah and we'll be calling a string can be initialized oh sorry about this the user id can't be a string it should be added in so let's just say it's an int and last but not least is synced with cloud so we're to say async with cloud actually is read from from our database as an integer remember is synced with cloud as an integer so we're going to say we're going to first define a column for it is synced with cloud column and we're going to call it async with cloud and i mean i'm saying uh we're going to call it but actually we've already called it we called it is synced with cloud so just need to copy and paste that in here you see okay and then we're going to say is synced with cloud as equal to now you see we don't have this uh data we don't have this field as a boolean in the database we have it as an integer so we have to read it as an integer so we're going to say in the map there's a column called async with cloud column and it's an integer okay if that is equal to one then return true otherwise uh is equal to one true otherwise false so you see what happened here we read the column as an integer and oh if it's equal to one then this guy is equal to true otherwise this guy is equal to false okay now that we've done the initialization of our database notes from the from the row we need to go ahead and we need to create the tostring as well for our database note okay so let's go and overwrite to string like this and we're just going to say this is a simple note we're going to say is equal to note and its id is equal to dollar id is text is equal to or just its user id is equal to dollar user id which is a field that we have and then we are not going to print its entire scene is an entire text instead we're going to say is synced with cloud is other is synced with cloud just like that all right all right so yeah i mean optionally you you may also add text if you want to it's kind of up to you but the problem is that the text of a note could be so long that it actually gets in the way of you getting information of your class instance such as its id user id and a single class so maybe if you want the text to be there just add it at the end so it basically doesn't disrupt the rest of the fields that you may actually have interest in reading okay so we did the implementation for from uh tostring right now but we haven't done the equality so let's go and overwrite the equality as well and the hash node hash code sorry i'm going to copy that code from our database user and bring it into the database node and i'm going to then paste it right here so you can see it as well we're in the equality we're saying that we're comparable with a database note as long as our id is equal to the other id then we're good to go for the hash code then we're going to get our id's hash code all right just like we did for the other class wow that was a lot of work to do okay now we've created the database note as well as the caption indicates um so what we need to do now is just to make sure we have all our constants in place before we carry on now remember right after doing these classes we're going to go ahead and create our um the actual note service that talks with our database all right so before we do that let's create all the necessary constants such as the file under which our database is going to be saved so let's just call it bb name and we're just going to call it notes.db all right remember this is like the file name okay now we're going to create and you can see in here in our um file here in as db browser for sqlite we call this file testing.db and in our case we're just going to call it nodesdb and we're going to store it in documents folder inside that application okay and then we have two tables and notes table and a user table so let's go ahead and create them notes table is um votes and const user table means user and these are like table names as we define them here node and user okay so those are those and what else do we need um i think i think that's pretty much it to be honest with you i think these are all the constants that are needed in order for us to be able to create our notes service all right let's go ahead now and start with our note server so i'm gonna clear this go to the top of this file and then i'm gonna make some empty space in here and actually create our notes service so let's go ahead and create a circuit class here and call it node service it's very exciting this is the beginning of us creating a cross service that works with our database which we're soon going to create actually okay as the cache indicates we need a function an async function that opens the database you see opening a database is not a functionality that you can just say open now it it will happen asynchronously because we may need to for instance grab the current um current uh folder do documents folder and then append or join that documents folder with our database name which we define here as a console so it's a lot of asynchronous stuff that we're going to happen in there well not a lot but a few at least and that is the reason this open function is going to be asynchronous okay so as i caption any case let's go ahead and create a future void and call it just open and we call it async like that now this open function is going to keep hold off i mean after it has opened the database is actually gonna store it somewhere in our node service so it's going to say hey i've opened the database here is the object so that other functions in the future such as the functions are going to let us read users from the database or you read notes from the database those functions then they're going to say ah oh here's the database instance i know how to grab values out of it okay so what we're going to do is to say we have a database as you can see it is brought by our sqflite library and we're just going to call it db all right so to begin with is null and we're going to assign to it all right um so what should we do now um let's go ahead then and start by doing a test and see if this database is already opened you see if we have an instance of this database then we can kind of like assume that this database file has already been opened and we don't have to open it anymore so let's just say if the db is not null and just throw uh a new exception and we're gonna just call it a database already open exception so let's go and define an exception uh here let me see if i can copy and paste that from my notes but you see this is just an exception that's a database already open exception all right so in here we're just going to say database already open exception all right simple if you call the open function multiple times while the database is already open you're going to get an exception okay so that kind of makes sense so let's go ahead and now get the document directory path and we have to do a try in here because this can actually throw an exception so let's say find final docs path is equal to and you need to say get documents get application documents directory if you have a look at the signature of this method it says i return a future of directory so let's go ahead and do that so we need to await on it and that's the reason our function is async and that's the reason we're awaiting because this returns the path asynchronously now if you look at the documentation for this you can see that it can actually throw an exception called missing platform directory exception if the system is unable to provide the directory all right if for some reason this the system isn't able to provide a document directory to um to us is going to throw this exception and that is exactly why we have our code inside a try statement here so let's say if that exception is thrown like this then we're going to throw our own exception so let's define an exception we call it unable to get documents directory this so it's just a class unable to get documents directory exception nothing special about that okay and then we in here we say throw at uh the name missing platform oh i see you see it's it's complaining now and i can see that you couldn't see the codes i apologize for that it's complaining and saying that i can't find this missing platform directory exception and that is because this is specified in this um path provider but for our path provider we just say show get get application documents directory so all other symbols are hidden from us so we could just remove that and just import the entire path provider and that error goes away all right okay now let's do this now let's say i apologize let's get the the actual path of our database so to do that you will say and what are we calling it db path is equal to join remember we have this function joined here that we imported from path and we say join the docs path the path and our db name remember the db name is a constant as a string we define it down here we just call the notes db that is now going to be joined with the actual path of our documents folder all right and what we're going to do is we're going to say we now want to open the database with a function called open database which comes from skflight and the path is dbpath and remember this open database i believe is the future of our database you see so we await on it all right and then we assign that to our uh local database instance that's it so that was basically opening the database so we've now opened it but remember all we've been working on right now is inside this db browser for sqlite this thing this program here is managing its own database file this database file is not going to exist in your flutter application we've just played around i just showed you how to create a sqlite database how to create different tables what fields are what primary key is so you need to kind of like forget about this this application and where it stores this data you need to now focus on how is your flutter application going to be able to create those tables how is your flutter application going to be re reading data from the tables or deleting data from the table so if you think about it if you've completely forgotten about the db browser for sqlite then you could just say at this point in time you see open database also can create the database for you if it doesn't exist we can look at the documentation for it here uh oh my god opens the database at a given path by the system uh on is the first let's see encrypt is called if the database did not exist prior to calling opendatabase okay so it can create the database for you which is what it's gonna do but those tables are not gonna exist and we have to have a way of creating those tables if they don't exist upon us opening the database okay and that's what we're gonna do here so let's go ahead and actually grab the code for creating the user table so i'm just going to say const create user table is equal to and this is now i'm going to actually use the syntax that we haven't used before and that's triple quotation marks okay and then triple quotation marks on the next line and then a semicolon now what this does is that it allows you to place pretty much anything inside this string without you having to escape that string because triple quotation marks are very unique so if you paste any program other programming languages code in here chances are that programming languages code is not going to include three three quotation marks so the purpose of this is that now you can go ahead in your sqlite uh db browser for sqlite and grab those users um if i go here database structure user modify table and you can literally now grab this code that was created by a db browser for sqlite and paste it in here you see so there we go now you have a beautiful database creation code in here sorry table creation code that says create table user blah blah id integer not null and however we need to take care of something in here and we just say if not exists i believe and we have to put it before user as well so that's the only thing we're adding here we're basically saying create a table call user if it doesn't exist because you see we don't want to get an error because if you create a table that already exists in the database then skflight is going to throw an error saying that this table already exists okay so that's why we need if not exists and then what we need to do is to tell our database this database that we created up here to execute that command so we're just going to say execute and you see it says give me a sequel to execute and i'm going to give you a future void and we say okay execute create user table and we have wait on it some comment in here we just say create user table and then in here for the um after we've executed the create user table we also have to then take care of uh the creation of our note table so i'm just going to do the same thing that we did up here and just say create note table equal to as single quotes triple single quote semicolon let's go to db browser for sqlite and grab this node here and say modify table and grab the code that was generated for you and just paste it in here do some formatting so it becomes a little bit more bearable to read and have a look at and we do the same thing that we did up there we say if not exists like that all right so i think i think to be honest with you we're good to go there i don't think we need to do anything special in there we also have to execute that command so i'm just going to grab the code from there paste it right here and like that and i'm going to say create note table so that's going to do the creation of the note table as well well done that was it that was a big function i mean by the standards of what we've done so far that was quite a big function okay but generally this is not considered such a big function i remember now you have actually constants in here you could you could i mean if it's me deciding i would bring this constant somewhere else not inside this function we could literally go ahead i mean i hadn't planned for this but let's go ahead and grab this constant from here and bring it to the end of this file okay where we have all the other constants like this and let's go and grab the other constant from here boo and bring it down as well so we put it at the end of our file right there okay as i said i hadn't planned for this but i just think it makes sense because now our function is a lot cleaner to have a look at here we have a comment for create the user table let's create a comment as well here we say that creates notes table and remove those empty spaces and just save your file perfect now we have the open function let's go ahead and have a look at how we can do closing of our database right let's have a look at my notes in here okay let's have a look at our closing code so i'm going to fold the open function in here so we don't see it anymore and let's go ahead and create as you can see in the caption we have to say future void close um okay and it's asynchronous so what we need to do then is we shouldn't allow any person to close the database if the database is not open so let's go ahead and define an exception for that and we're going to call the database is not open okay so i'm going to copy that exception so i don't have to type it manually manually because by this point you know how to create exceptions so it's nothing extraordinary for you to learn database is not open that's a new exception okay so what we're going to do is we're going to say we have our database final db is equal to our local db up there and we say if db is null and then we throw database not open oops database is not open else we're gonna ask skflight to close that database for us and the way to do that is just to say db.close and you can see it's a future of void so that's why we're waiting on it all right and then at that point we have to also reset this local database which is called underscore data underscore db so we say db is equal to no right so easy peasy close went very fast actually all right now what we need you see as we're now as we have to open and close now we're going to start working with data in the database but in order for you to get like your um database so that it can for instance actually grab like every function that tries to read something from the database it has to have some code in order to make sure that the database is open otherwise it has to throw an error so we're gonna have like five six of these functions and each of which is gonna check the database and then do the same thing is the database open yes if it's not open throw this error we could put that particular code inside on our function that we are going to call getdatabase or throw okay so let's go ahead in here and just say this function returns a database it database or throw and prefix it without underscore saying that this is a private function and then we're going to say final db is db if db is null and we say throw um database is not open else we return the db okay so this is a private function that our reading and writing internal functions in this class are going to use in order to get the current database so that they avoid doing the same if statement everywhere okay all right now we're going to start with actual code so to read and write from the database in this case we're gonna start with a function called delete user that allows us to provide as you can see an email address and using that email address then we're gonna delete that user from our database so you you will learn how to manipulate data from our or inside our database okay so let's go ahead and do that function signature as it's indicated here i'm just going to say future void delete user and required uh string email and make this function asynchronous okay then what we're gonna do is just to get our database with this absolutely beautiful get database or throw function that we created here so i'm just going to say final vb is get database or throw so this in turn is going to throw an exception called database it's not open if the database is not open so we don't have to manually do that okay so in order to delete something from sql flight uh or in this case sqlite that is managed by sqflight we can say db dot d b dot delete and as you can see it returns a future of the number of rows that were deleted and then it says okay which table and then a where clause and a list of objects to pass to your word clause so we're going to say the delete from the user table and uh the word clause is gonna be email is equal to something and the where arts are in this case are gonna be email to lowercase okay so i'm gonna put this semicolon there and a call in here and then we're going to wait on it and we're going to say final and delete the account is a weight so in this case i mean as you can see here is what we're basically doing is just we're doing formatting we're going to say we're going to say delete something from the user table as long as that something's email is equal to something and that something is again that email so you're basically saying delete as many objects as possible in the user table as long as their email is equal to this and remember we made email unique so if if we've done our homework right then deleted count is it should either be zero meaning that no personal account or no user with this email exists in it into table or it should be one meaning that yeah i could delete uh without a problem so we're actually gonna assert that we're gonna say if deleted count is not one all right then we're gonna throw an error could not delete the user so i'm gonna grab that um exception i'm gonna place it right here so we say if we couldn't delete that user we're just gonna say throw could not delete user all right so we couldn't delete that user um all right so let's go ahead now that we have done the delete user and and remember you may be asking okay why are we throwing a user maybe that user doesn't exist and it should just work fine and of course i mean it is going to work fine if you have your try and catch statements when you call this function what we're saying is that the interface of the node service is going to throw an error through an exception if you call the lead user with a non-existing email and that's completely fine for a service to do but where you're consuming the service then you can manage and say oh this delete function is going to throw an exception by like for instance looking at a documentation looking at the code then i'm going to handle it where i'm calling it as at the call site which is called okay so this is completely fine for a service to do then what we're going to do as the next point is to create a user and you can see it's going to be a future of database user so this is beautiful it's going to actually create a user given an email address and then it's going to return that database user to us so let's go ahead and do that let's just say future database user and we're going to say create user and a required string field of email and we're going to make it asynchronous all right so in here what we're going to do is just going to get the database we're going to say final vb is equal to get db database or throw and then we're going to say um db.query um like that because we're going to actually issue a query to the database okay so as you can see this is a helper to query table and return items found all optional clauses are unfiltered or formatted as sql queries okay so um let's go ahead and in here what we're going to first do the first thing we're going to encrypt user now we're going to actually check if a user with a given email already exists okay and that's where why we're doing query and we're not like inserting something into the database to begin with we're asking the data to say hey does in the user table we're looking for and we're acquiring the database for a person or a user whose email is this and that this thing is actually going to return and let's have a look at it it's going to return a list of rows that were available in the database okay and that list is going to be empty if no no entities matched our query okay so let's just call it final results is we're querying the user table and we're going to say um we're looking for just one item and we have a word equal to we're looking for the email and where arts are going to be email to lowercase semicolon at the end and bring it like this equal to bb and we wait okay so by us first making a query to the database and checking whether a user with the same email exists we're basically avoiding getting an error for the uniqueness of that email later on at the sql layer so in this case you can see results if i move my mouse over it and it says that it is a list of rows and if this list is not empty it literally means that a user with that co without email address already exists in the database so let's then say if results is not empty then we're going to say throw user already exists uh exception and we don't have that exception yet so let's go ahead and find that exception for me at least and i can paste it right here so define this exception use already exists and let's go ahead and throw that exception user already exists okay so that's the our if statement so at that point we've basically made sure that that user does not exist in the database all right so what we need to do then is to go and insert that user now that we've checked that he or she doesn't exist in the database so we have to go and insert that user so the way we do that is by going and telling our database we say db insert and you can see it says in which table and then give me a map of keys and values which is the column name and the value for that column all right so let's just say we insert into the user table which is a constant we've defined from before remember and then the map is going to be for the uh let's go back to our db browser for sql for note sorry for user uh oops for user we have id which is primary key not null and auto increment so we don't have to insert the id but we need to insert the email so let's go ahead and say we have the email call is equal to b it's going to be equal to email to lowercase all right so like that and insert if you can have a look here it returns a feature of pins and if you read the documentation uh let's see if if it gives us some documentation here zero could be returned for some specific conflict algorithm algorithm algorithms if not inserted so this is going to basically give us that uh so what it's going to do in this case is actually going to give us a user id back i wish there was some good documentation about it oh here you can see it says insert returns the id so this is very very good this is actually really cool because remember we said we return a database user and a database user actually has an id in it so if this function here did not return the id how else would we get the id then we'd have to insert and then read that same user in order to get the id but we don't have to do that so in here then we say final and we say user id is equal to await on this function functionality and then we just return a database user up so you actually see the code then we say user id and the email is email the way it was before they added a column there fantastic now we've taken care of the create user uh function in our database so that's create user i'm gonna follow so now we have create user delete user and open and close and a private function in order to get the current database okay as the caption indicates now we have to take care of a function called get user which it can retrieve a user given its email address alright so i'm going to go ahead and basically write that function signature in here by pasting it from my note so i don't have to type it manually but you have it in the captions in case you need to go go to it we just like we did in the other functions we're going to get the current database or throw an error if the database isn't open so we're going to say db is get database or throw then what we're going to do is we're going to query the database for that email address and if you remember in the create user we already did that so let's go and copy that boof like this and i'm going to fold create user and let's go in here and paste that code we have the results okay so in this case we have to do the opposite you see in create user we checked to make sure that um the results are actually empty because we want to make sure before we create a new user with that email that email doesn't already exist but in this case we actually have to do the opposite when you want to get a user we want to make sure that it does exist so we have to say if results is empty meaning that we couldn't find this user with the given email address then we say a throw could not find user actually we don't have that yet so we need to define a new exception called could not find user and i'm gonna bring it up here just like we have to delete user we also have could not find user okay and then here we have to throw that could not find user all right if the results were empty then we throw it up otherwise we have to then construct a database a user so we say return database user from row and we say results dot first which is the first row that was read from the user table also remember we set a limit of one so it should be it should be either zero rows or one row which is the user with the given email address okay all right perfect uh let's go ahead to the next function that we have to implement and that is for us to be able to create new nodes so if you want to be like me and like clean up the code a little bit here just fold everything so you only see the function signatures now we can focus on the next function which is creates nodes i'm just going to find it in my notes here just to make sure i give you the exact code necessary in order to create the create note function uh if i can find it um creates notes right there okay as the as the caption indicates we have to have a an asynchronous function called create node it returns a database node and it also says who is the owner of this node and it's just going to create a new node with an empty text and it's going to associate that and nodes with the given database user and for you see the parameter is of type database user and a way to get a user is either to create one if it doesn't exist and you get the database user or you get an existing user okay so excuse me let's go ahead and say future database user and we call this function as the nodes indicate create node and we say it's a required field of a database user oops sorry it shouldn't return a database user it should be database nodes all right and the parameter is the owner which is the database user and it's an async function so just like we did in the other places we're going to say final db is get or throw get the current database or throw so what we need to do first is just to make sure that the current user that we are passing here already exists in the database because remember database user is just a class it can be created by calling its constructor which is right here um somewhere here so i could just create a new database user instance as a database user and a random email and a random id but in here when we're trying to create a node for that particular database user we need to first make sure that that database user's actually inside the database okay and to do that we say final bb user equal to await and we actually call our own get user function in here we say get user with the email of the um owner's email on our email so in here we're literally reusing the code that we've created then what we're going to do is we're going to check whether this database user is actually the owner see what do i mean by that i mean that let's say that i go and hack things up and i say oh i create a new instance of database user manually without inserting into the database and here's the id some sort of a random id and then here's the email which i know exists in the database now what we need to do in our code is just to make sure that the id that you provided in your database user here is actually an id of an existing user in our database and to do that we could literally use this little beautiful function that we wrote earlier which is the equality function of our database user which actually checks our id against the other database user's id so if we literally say here in here we say if the db user is not the owner which goes into our equal equal operator and negates it it says oh if it's not equal to that then we say throw could not find user okay so after this place if we if we actually found the db user with that email and the id was exact id as the owner then we can actually be sure that that user does exist in the database with the correct email and the correct id okay so let's just put comments here in here and say make sure owner exists in the database with the correct id that's it okay all right after we've done that we also have to take care of actually creating um the note so let's go ahead and create a um text and here we say the text is uh i'm sorry i noticed that you couldn't see that code i hope that you saw this code at least that i wrote here but if you didn't i apologize for that because just because i'm using a software that i don't see the software all the time on my main monitor which is the monitor i'm coding i have to look at a secondary monitor which is down here so i'm doing my best to look at that secondary monitor just to make sure you're seeing all the content but sometimes i could miss that i apologize for that so let's see that now you can see this code all right i'm going to bring this code a little bit up so let's go ahead and actually create the notes so i'm going to put a comment in here and say our work now is to create notes create the notes and what we're going to say we're going to say db insert just like we did an insert previously for create user we're going to do a db insert for the notes and it's in the notes table and you see the values in here is going to be a map and the map is if you look at the insert function is literally a map of string and object so let's have a look at our note table in here and you can see notes right click modify table it needs user id text and is synced with cloud columns so let's go ahead and say user id column user id call it's the owners id and we had what else do we have we have the text column and that is equal to this text that we just created out there which is an empty text basically you don't have to do this you don't have to do that part you could just literally just say this to me it's more readable if i define these things beforehand like that okay and then here we just say is synced with cloud column and its value is one in this case so we're basically saying that we start off with that okay and i just noticed that i had missed a column in there remember insert it returns the id of the inserted object in the database and it's a future so let's then say final note id is equal to a waiting on that function to insert the notes into the note table all right now that that is done we're going to actually return a new note instance and return it a database note so what we're going to do in here we're going to say final note is equal to database note notes like that and for the id we're going to say note id i'm going to bring it up so you see it better and for the user id we're going to say owner id text is text so this is another reason to have it defined like a constant like i did so that we can reuse it here and there and is synced with cloud what should we do there we should probably just say true okay creating a note you have to return it then inside your um asynchronous function all right i'm going to put a comma here as well just to make sure formatting is in place all right now we inserted notes into the database and we also created a database node to return that from our function wow a lot of code a lot of code but i hope you're sticking with me throughout this chapter so now we have create note as the caption indicates now we have to work on a function that allows us to delete a node because remember we're going to allow the user to select a node in the database later sorry select the node on the user interface which that user themselves have created and be able to delete that notes all right so we need a function that allows us to delete a node using its id all right so let's go i'm just going to bring the basics of this function or almost the entirety of this function actually here so we don't have to code that manually i'm going to paste it here and as you can see here the signature of this function i'm going to explain it all the signature up to this function is called delete node as an asynchronous function as the caption at the bottom of the screen in case we do the get db and then we're literally just calling the delete function which is the exact same thing which i believe we did in delete user let's have a look at that you see delete count db delete in the table and then your work clause and in this case inside the delete note we're saying from the note table delete an object which has its column id equal to something and then we're passing that something in the where arcs now if we couldn't delete anything if that note didn't exist with the given id and we're throwing an exception called could not delete node and that's an exception that we haven't defined yet and we're gonna have to define that at the bottom all the other exceptions that we've defined so far so that's could not delete node implements exception all right so i thought to i mean i usually don't copy paste code even if it's my own code but i thought this is such an easy code we have literally done every part of something similar before we've done the get db we've done the deletes before we've done this if statement before so it's nothing new and i don't think you have to have me here spending time explaining the same thing over and over again and that's why i copy pasted this delete note here okay all right then what we need also is the ability for us to delete all nodes from our database how do we do that as you can see we need a function called future means which is which indicates a number of nodes that were deleted from the database we call it delete all nodes and it's an async function here okay and uh what we need to do in here is just it's very simple we're going to say final db is equal to get or throw and then we say db delete and then we just literally say uh note oops note table uh boom boom await on it all right and you see this if you issue the delete command on on your database with a given table all what it does is that it deletes every row inside that uh table for you and it will return the number of rows that were affected so you can see it returns the number of rows affected so that's exactly what we want to return so just return that value in this function right perfect good stuff we've done some big functions and some small functions so it's so refreshing to have some small functions as well even for me so so what we need to do now is to create the functionality for fetching a specific node you see when we actually get to the ui where we render all the nodes that are inside the database to our user in the main ui of our application we're going to list all the nodes and then if the user presses on any specific node then we're going to get the id of that node and then read that node's information from the database and that's why we need a function that takes an id of a node and actually grabs that node for us from the database okay so let's go ahead and program that so i'm gonna bring bring the uh i'm gonna bring the function signature and we're not gonna copy paste it this time let me copy paste the function actually i mean so let's go ahead and get the db so this is easy for you now you know how to do that and we're going to query the database so we're just going to say final notes which is going to be like the iterable list of maps that the sqlite database can read so we're going to say await on the db query and we're going to say in the notes table i'm going to remove all these overlays so you see the code better notes table and we're going to just say um remit one because we want to get one note all right and the word clause is going to be um using its id you see we're gonna say id equal to something and the where arts are gonna be just the id itself like that boom and a semicolon like that all right and now if this notes uh which is you can see it's a list if notes is empty we're going to throw an exception so we're going to say um could not find notes do we have that uh could not find user we have could not find notes we don't have so let's go and define it i'm going to bring it from my own notes so we don't have to write that manually so define an exception called could not find node implements exception all right and then here we just throw it could not find nodes so if you gave us an id we couldn't find it in database we just throw an exception otherwise we need to actually create an instance of our database node so we say return database note from row and nodes first okay so that's similar to how we did it before for getting a user as well all right now we also need a functionality that allows us to get all nodes in the system you see we have get node to delete all nodes delete node create node but we don't have any functionality that can get all the nodes and that is the exact function we're going to use the main interface of our application to render all the nodes for a given user okay so let me just make sure that i have that function in here and it is called get all nodes let's see we can find a functionality get all nodes somewhere create note we have get user we have and perhaps i don't actually have a functionality right now i can see in my notes that i don't actually have get all notes but that is actually not a problem at all in the get note here you see we have that we have to define this gets all notes so let's go ahead and do that i'm going to copy the signature of this function and i'm going to bring it here and we're going to say we're going to return a future of list of database notes and we're saying get all notes like this all right excuse me and it shouldn't require any parameters we're just going to ask the database to return all the notes all right sorry about that again and i'm going to copy the functionality from here for gets notes excuse me again and in here we're not now going to limit anything and we don't have anywhere clause okay so just like that we're going to say db query from the note table and we get all the notes then if notes is empty then we say could not find notes or perhaps we could just say notes we can see it's a list we can literally not have any special logic in here that says could not find note or anything and i'm gonna have a look at my notes in here that's fine um what we need to do now now that we have our notes we can map them so we say notes map and you can name this parameter and and in your mapping you need to say okay i get a database note which which you can see is of type let me see if i can move my mouse over here it's a map of string object this matches perfectly into our database notes but from row and then you say from this n let's actually call it note row or something like that and we put it there and if you say final result and now i think this is an eye treble to be honest with you so you can see it's an iterable of database notes okay so what we could do is actually change our future in here instead of saying list we return on iturble okay so in order for the sake of uh cleanliness i'm also gonna change our captioning here and say iterable so you see the correct information on your screen as well all right so that's our result so all we need to do in here just to return it that's it so so like that perfect so um and that's the functionality of get all nodes so it's very simple nothing nothing special and now uh what we need to do is just to wrap it up there's one last function that we have to implement and remember when we go to the main ui of the application we're going to allow the user to create nodes list all their created nodes and also be able to click on any specific node in order to update the contents of that node so we need a function called update note so let's go and bring my notes in here update notes so let's go ahead and create the signature for that function and future database notes and we say update notes like that and we're going to have some required parameters which we actually grab an existing database note object and then we expect the user to also provide a new text so let's just say required a database note notes and then we say it's the required string of text just like that you're already familiar with this we're gonna get the database we say get or throw okay and we're just gonna issue an update to our database we haven't done updates before for our sql like database so that's what we're going to do now so let's just say db.update and you can see it says give us a table or give me the table and your list of updates so let's go in here and say update the uh note table um and actually before doing that how do we make sure that this table that note already exists in the database because like we saw earlier anybody can go and add or create an instance of a database node it doesn't necessarily have to be in the database but we kind of need to make sure that it already is stored in the database because before we can updates to update its text so we already have a functionality that does that remember gets notes with an id so we could literally just say await it's note and then we say note id and you see this actually throws an error if you go to this function it throws an error called could not find note which is exactly what we're after but we're not actually after the the result of it we don't want the actual note because we're assuming that that is the same object as this so we're just ignoring its return value okay in the update we're going to say the notes table and the values that we're going to provide are two we're going to say the text column i need a new text and we're upon you updating the text of a node we're also going to assume that well all of a sudden this node is not synced with the back end or with the data with the uh with the cloud database anymore okay so that goes back to our um async with cloud column so let's go in here and say is synced with cloud column then it's going to be set to zero remember that was an integer field all right update is an asynchronous function so you have the weight on it and it also returns the number of feel a number of rows that were updated so we're going to say updated updates count sorry final updates count is equal to a weight on db update all right now by you at the call side calling the updates note function we're assuming that that note should have existed in the database okay so in this case the updates count should it should be a value other than zero okay so we say if updates count is equal to zero bring the code up so you can see it and then we have to throw a new exception called could not update note and paste that exception from my notes so it should look like this class could not update node implements exception all right so i need you to write this code as well and if updates notes if updates count is zero then we're gonna say throw could not update note else now you can see what we promised is to return a new database note so let's go and just say do we then i mean that's that's the thing we've updated that uh and how do we return an update a database note to you well we could just do this turn its uh notes with that note id because we already have gets notes function implemented all right wow very well done if you could stick with me throughout this chapter because we did a lot of work so um i'm gonna fold this fold this you can see we have a lot of functions here quite a lot of work and i think so far this has been the biggest chapter of this uh of this course but we've also had a lot to do a lot of information i hope you could stick with me let's go ahead now and clean up our exceptions as the caption indicates let's put all our crowd exceptions in one file inside lib services crowd crud underscore quad exceptions okay so let's go in here and uh actually it should say crowd slash crowd exceptions so um if i look at my notes inside services crud i'm gonna fix this caption and i apologize for that i'm just gonna fix it on on the go like this and i'm gonna bring it up and actually it should say crowd slash crud underscore exception so i think there was more than one error in there and cros required exceptions so it should be lip services slash quad exceptions all right so let's go and fix that up inside services we have crowd already and we have nodes service dart let's create a new file in there and we just call it crud exceptions dot art now i need you to go into your node service dart file and grab all those exceptions that you define here and just cut them with command x on macintosh or control x in linux and windows and then bring it into your quad exceptions alright and save this file and let me also have a look here just to make sure my notes are clean as well for you uh so because i i noticed that the next caption was also a little bit incorrect now we need to go and use that crowd exceptions in our note series because as you can see it is marked as red right now because there were so many exceptions thrown that um this file doesn't have access to anymore so i'm gonna get help from visual studio code here with command dot and say import crowd exceptions and all those errors are gonna go away all right well done huge chapter a lot of work done and congratulations for sticking with me through this chapter now as is the tradition we're gonna now go ahead and commit our work and um also tag it so i'm going to make the screen a little bit bigger let's go to our terminal here and i'm then going to say in here we're going to tag and commit our work as step 11 so let's first get status and then we say git add all hit status again here are the things we've done pop spec was changed because we added three dependencies uh provide a path provider path and and also i believe actually it was called path and path provider right yes path path provider and sqlite so that's why these two files have been changed node service is completely new and crowd exceptions is also new so git commit uh step 11 as the caption indicates um git push which they commit first remember and then we tag it as step 11 and we push our tags as well fantastic now congratulations again for going through this chapter with me it was a huge chapter i think the biggest so far now we need to get ready for the next chapter as a tradition for the other chapters at the end we talk a little bit about what we're going to do in the next chapter just to get ready for it so we've done a lot of work on the data now we need to fuse it together with our uh with our ui and in order to do that we need to talk about streams and stream controllers you see when you're in the main ui of your application after you've logged in you need to see a list of your notes but what happens if you see the list of your notes and then you press the plus button to create a new note and this plus button is a button that we're going to create soon in the next chapters what happens if you press the plus button should you then send manually a signal to your ui and say hey a new note was created update the list that is a lot of work and for that you can do things a lot cleaner if you use streams and stream controllers and that's what we're going to talk about in the next chapter so you may want to have a short pause after this chapter since it was so big so do that please get your refreshments coffee tea whatever you want and i'll see you in the next chapter hello everyone and welcome to chapter 28 of the swata course in previous chapters we've been talking quite a lot about crud create read update delete and we talked about how we can for instance have raw functionality in our node service so that we can read from the database delete stuff from the database create users etc etc now we haven't really worked in the past two chapters so much with our user interface and that's completely okay because sometimes as you're developing applications or you're developing software you may have to take detours in order to create the functionality that is later gonna be needed for your user interface and you'll do the same thing if you're doing um back-end development like uh web development so i myself do web development with django and sometimes i have to go and create a lot of functionality on the backend first before i can actually go and mirror that functionality on the ui which is for instance the web browser where the user is consuming the content so and if even if you're a designer for instance you're working with figma you can't always produce user-facing content like prototypes you may have to sometimes go and design for sure components and then after you've done your components and you'll be ready to put those components into screens and display that to your product owner or your developers so um so far we've been working a lot with what the user doesn't see and we have to like stitch up those last bits and pieces before we can actually go to the ui and manipulate that data which our notes service can right now manipulate we're missing a few functionalities which we're going to develop in this chapter in the node service and what we're going to work with in this chapter especially is with streams and stream controllers so let me bring up the caption that i'm going to talk about now so what are streams and what are stream controllers well if you are a developer already you've done software development you may know something uh about reactive programming and reactive programming is where you have a bunch of data sitting somewhere for instance and then you perform some operations on that data and this data gets updated and you will be notified of these updates through some sort of a pipe of information so and if you haven't done software development before so reactive programming and streams and stream controls may be a little bit overwhelming but we're going to start very slow so there's nothing to be worried about i'm going to explain everything as much as i can to make things easier for you but if you don't have development background from before software engineering background there's not so much that i can explain about streams and stream controllers for you to completely understand how they work all i can say is that imagine a stream is just a point of time or a stream is basically an entity that controls data all right just say something that keeps hold of data and then you perform things on it so you say add this data or remove this data add this data with this data and give me the results so it keeps hold of its data and it has a timeline so it starts at some point manipulates its data and then it either errors out at the end saying that oops i can't do this and then it just dies or it will just complete at some point and also there is a third category of streams where the data just keeps living on so it never basically um completes or errors out so so just think of streams as pipes of data types of information that you can manipulate and you can also perform operations on so if that's what streams are then what are streams stream controllers in dart a stream controller is your interface um to your streams so you have the stream which is sitting right here and you can't you you don't basically usually go and add stuff to a stream directly or read stuff from the stream what you can do is to have a stream controller where you're manipulating the stream for instance our node service and this stream controller is able to for instance add stuff to the stream or read stuff from the stream so just imagine the stream controller is kind of like the manager of that stream so if all of this sounds a little bit um high level and abstract i completely understand that it usually is when you're working with reactive programming some people actually hate reactive programming but as one of my colleagues used to say it's always easier to hate than to learn and my approach is usually if i hate something is because maybe i haven't really fully understood it so there are very few things in my life that i've actually learned which i hated after learning so if you're a bit overwhelmed by streams and stream controllers or reactive programming don't be they're actually really good if you know how to use them so they're very easy to use as long as you get a handle of uh how basically it's getting a handle of the right way of using them so that's what i'm going to show you in this chapter and then upcoming chapters as well so let's go excuse me let's go to our application i'm going to put the code right here let's have a look at what we've written so far i'm going to increase the size of the screen and then decrease the font size a little bit so it's not as ginormous so um let's have a look at what we've done so far you can see we have quite a lot of functionality in here we have for instance delete all nodes then we have get all nodes we have update nodes so quite a lot of functions but if you see all of these are directly talking with our database with our sqlite database none of these functionalities are actually telling or we don't even have to talk about functions but if you look at the node service in it itself it doesn't contain a list of nodes so it doesn't have the ability to cache these nodes so it's as soon as you give it a command the node services i don't know what to do i'm just going to go to the database and do what you said i have to do however this could i mean in not in our application but in an application that has millions and millions of rows of data for instance this could not be such a good idea that you always go to the database and read the entire thing in order to for instance delete one row or um basically these operations should kind of be like cached inside your application before you go and hit the database hopefully and what we're going to do as you can see in the caption here we're going to actually start caching a list of notes that the node service has so the goal is for the note servers to be able to expose a list of notes that the ui can then render on this on the user screen so if the user goes and presses the plus button then that plus button is then gonna send a message here to our note servers we're going to then go to this function create node and this create node function internally is then going to manipulate that list of nodes inside node service say hey here's a new node add that and then our ui is going to listen to a list of these notes available in note service and if things change in that list then the ui is just going to automatically update itself and this interface between the ui and the node servers is going to be done through a stream okay i know it's a lot of a lot of information but you'll get it you'll get it as long as we go through this chapter together so what we need to do first is let's go and as then as the caption at the bottom of the screen indicates we're going to go and expose a list of notes in our note service okay so let's just let's go ahead and say we have a list of uh database notes and we're just gonna call it notes and we're gonna start with an empty list all right so that's really good now we have let's say this is our cache this is where we're keeping all the notes that this node service manipulates all right so now let's go and talk a little bit about our um stream controller so you see what we need to do as the as the information here says um what we need is for the node service to be able to control a stream of nodes so when the list of this nodes changes we need to tell our stream in the note servers that hey some element got added hey some element got deleted or some element got updated so then the ui can then reactively listen for these changes in the in the nodes service and we do that through the um our stream controller so let's go as the caption indicates i'm going to write it and notes actually maybe i should yeah i'm going to write it notes stream controller and the way to create a stream controller is that you just say stream controller and then you specify the type of data that your stream contains which is a list of database nodes and then we're gonna just say dot broadcast like that and i believe stream controller isn't yet excuse me um isn't imported in our notes service so i'm gonna get help from visual studio code and you can see it's it says that well stream controller is available in the dart async package so um and yeah async meaning asynchronous so in order to be able to use stream controller you have to import that so i'm going to get help from visual studio code to do that all right so let's see what we did in here what is this the syntax looks really really scary but it really isn't all you're saying is that i want to be able to control a stream um of a list of database notes basically you're saying that i have a pipe this pipe every event that is inside this pipe is a list of database nodes so let's say you start with an empty list so this list is empty inside this pipe then you add an item to this pipe then what it does it says oh what was i before i was on empty list add that new item so now i'm an item now i'm an array or a list with one item and then it puts that array inside the stream so the stream's value is now at the beginning was empty list then it's a list of one item so this stream controller is basically in in control of as its name indicates it's in control of the changes to this notes um list it isn't hooked to that yet but that's its purpose and that's the reason it has the exact same data type in its stream controller now the broadcast part in here and as you can see the documentation actually spot on it says the controller where stream can be listened to more than once and if you've done dark development or flutter development from before you may know that if you then um and i'm now assuming as i said that your dart or flutter developer from before if you have created a stream controller and then you go and listen to the changes to that stream that the stream controller is controlling and then you do a hot reload then you get an error from your flower application saying that oh this stream's already been listened to so you cannot listen to it again and that's the problem that normal stream controllers can cause and that you as soon as you've listened to them you should close your listening channel to that stream before you can listen to them again so that's what broadcast fixes if you're not a developer from before what this broadcast basically is saying is that it's okay for you to create new listeners that listen to the changes to this stream controller so here's a pipe of information at this point you start and listen and then it's completely okay that if you want to listen to changes to the stream controller later in the future as well so you're not going to get any errors by doing this broadcast all right all right um now what we need also is a handy function in our um in our application.can that can read all the available notes from our database and then cache them inside both the notes cache right here and our controller okay so you see what our our goal in this chapter is is to make sure that this is the source of truth that our notes list contains all the nodes for for instance the current user then the stream controller is our interface to the outside world the ui is going to be listening to changes that occur in this stream controller so whenever you see this this is not something that's going to be read from the outside everything's going to be read from the outside through this all right so keep that in mind so let's go ahead as a caption in the case and we're going to create a function in here called cache notes and its purpose is just to read all the notes from the database and place it both in here internally and in our node stream controller which is going to be read externally all right so let's go and do that so i'm going to say future void and we're going to call it cache and notes is async then if you remember we already have an async function called get all notes so i'm just going to say um final uh all notes is await it's all notes okay so that's gonna get all our notes and we're gonna assign that to our uh list of notes in here okay so let's go in here and say as you remember get all notes returns on iterable of all our notes and now we have a little bit of a problem here because we're saying list of all notes and in here we're also saying list of notes so we have to convert that terrible to a list of all notes okay either we could do that or we could have this just sit there as an eye treble it's completely up to you i have no issue with any and we could just go with list so let's go in here and then we're gonna say uh our notes is the private notes is all notes to list and we also are going to update our stream controller with that with the value of underscore nodes okay so we're going to say notes stream controller if i can spell and then we're going to add notes to the stream and remember a stream is just the evolution of a value through time and the first point of this evolution was an empty list and then the next one is going to be the notes that are all the notes are in the database okay so that's just that we telling anyone listening to the stream controller that hey here's a new value all right okay so um now that we're doing this you can see we're getting an error and dart is very actually this analyzes so clever because you see it's telling us that the cache notes function is not being used now you may be asking yourself well none of these functions are being used update note for instance is not being used so if i search for update notes let's see update nodes could not update nodes so yeah you can see that update node function in itself is not being used at all so why is it that the analyzer is complaining about this function particularly and the reason is because we have a little prefix behind this function name and this prefix is telling the analyzer that this function is private and private to this class now dart analyzer is looking at it and it's like okay it's a private class but you're not using it so the reason that other functions aren't being um marked with this warning is that dart understands that they are not prefixed with a with a with an underscore meaning that they're going to be used publicly somewhere else so it's not going to yet give us any warning saying that you haven't used those functions as soon as you remove that you see that the warning also goes away but we're going to keep down the score okay i just want to explain to you why you're seeing this a little warning here okay now that we've done cash notes what we're going to do is just to go to our as a caption case we're going to go to the open function let's see if we can find it here open and upon opening our database so uh let me have a look at my notes upon opening our database we are going to um cache all those uh let's let me just have a look at my notes yeah we're gonna basically go to uh the open function that we have here future void open i'm a bit surprised that i actually haven't written any notes about that yeah i can see actually i have so that's good okay so right after executing this command for creating the notes table after we've created the user table and note table and now that we know that we could open the database we also have to cache all the notes in our local variable so let's just go and call that function so we're just going to say await cache notes okay so this means that when you call this open function if after we made sure all the tables everything is there if they didn't exist then we're gonna read all the notes and place them inside this notes variable and also in this stream controller okay so that's how we did the cache notes and i hope that you could see the see the code and it wasn't hidden by the caption at the bottom of the screen all right so that part is done now um now what we need to do in here is to go to the next part of the code and as you can see it says cache note in create node in create node function add the new node to underscore nodes and the node stream controller so i'm going to go to my nodes here creates nodes and ensure that when we create the nodes in our creates node right here in this function in the create node you see at the moment what we're doing is that we're just creating a node and returning it that's good but i mean it's not good enough because as i said we need the ui to be able to reactively listen to all the notes that are right now in the database for that current user okay so in here after we create the note we're actually going to add it to our array of nodes and then we're also going to add it to our stream controller so i'm just going to go in here and say nodes and add this new node in there and also remember the stream controller's responsibilities just reflect the values inside the underscore nodes to the outside world so all we have to do is just to say notes stream controller add notes just like that because notes is the source of truth as i mentioned before all right great stuff uh now we need to take care of the other function called delete note let's search for that um delete notes all right so what we need to do is to have a look at this uh functionality here and you can see it says if we couldn't delete anything then uh throw this exception but now we're gonna add an else statement in here and by us being able to delete that note meaning that you can see the note id we have which is this id so what we need to do as a caption in the case we need to actually remove that note also from our local cache so we're going to say notes remove where and this is the note and then i'm going to say note that id should be equal to that id after doing that we could just say note stream controller add notes and you could be try you could try to be clever in here and you for instance could say oh you see that who says that that note actually exists in our cache we can't 100 be sure about that but if you look at the signature of the remove where function um removes all objects oh maybe we don't have the ability to actually know if that node was deleted but what you could do you could just say count before is notes count and then you could in here or length and here you could just say if notes links is not count before then you can update your stream i don't plan to do that but you can you can try to do that if you want to it's just a safeguard for you to say i'm gonna update my out outside facing stream only if i actually could delete this note from my cache if you think it's worth it i don't think it's worth it but that's just an opinion so we're going to leave it like this as the caption also indicates now you see we also have a functionality to delete all nodes so let me find that function all nodes all right so let's go in our delete all nodes in here find that function and you can see right now what it what it's doing is just returning the number of deleted nodes now what we're going to do we're going to say final uh what should we call it number of deletions is equal to this and we're gonna return that number of deletions okay because i mean i'm doing that simply because we need to do some work in in the middle here okay so then what we're gonna do is gonna say notes is an empty list all right so we're resetting the notes and then after doing that we're also going to update our stream controller so we're going to say add the underscore nodes to stream control and then return the number of deletions so let's make sure that our local cache is updated and also that the user-facing interface of our class which is the stream controller is also updated with the latest information okay next thing that we need to do as you can see in the cache that says update caching get node remove old node with same id and add the new one on and update this stream so let's go to our git node okay so um let's have a look at our get note in here then and at the moment as you can see in here what it's doing is oops that's not get note um here is get note right there okay and as you can see here uh we're basically what we're doing is that we're saying um upon you trying to read a note from the database we're literally just making a query to the database and then if we could find that item we are returning it by creating a database node from from a row that you can see right here uh but what we're gonna do is that if you try to get a note in there is a possibility that we already had that note cached locally in our notes array but that note is uh outdated meaning that the copy that we had in our cache is not really updated with the latest changes that have been applied to the database so it makes good sense right here to now upon creating a new instance of database node actually to update our local cache as well okay so i'm just going to say final note is equal to that and we're going to return that node bill right here so this code is the exact same as it was before except we're now assigning the return value of from row to a new local variable here okay so let's go to our notes and say remove where and i'm going to say in here note and i'm going to say i'm going to say note id should be equal to id which is this thing here okay so we first remove that node existing node from the notes array then we say nodes add and we add the new nodes in there and then what we're going to do is right after that update the stream controller which is our outside facing um interface so note stream controller add notes okay so you can see this pattern so we first always update our local cache and then we reflect those changes to the outside world all right all right great stuff so um that's for note stream controller and notes um [Music] now there's another function which is called update notes and let's go to update node actually before we have a look at anything else and you can see in here when we update that first we make sure that that node exists so let's put actually a comment in here make sure note exists and then we say update db i'm going to expand this code so you see better that's the update db part and if we couldn't update anything then we throw it could not update note and you can see that in here upon doing an update node what we want to do is i mean it is quite clever what we've done so far because it means that we've updated the database but what we do then in order to return the new refresh node is that actually we call getsnow so that is that's pretty good so but what we also need to do is just to make sure our local and cache is also updated so let's go in here and say final updated nodes and what we're going to do as the caption at the bottom of the screen indicates we're going to remove that notes from our local cache and add the updated note in there and then send the add message to our stream controller as well so let's just say notes and remove so we're going to remove the old object from our cache and i'm just going to say notes as long as the notes id is equal to the updated notes id so that's going to remove the existing existing node and i'm going to say notes add and we have the updated node in here as soon as you change your notes and local cache then you need to also update your stream so the stream controller add notes all right and then we return the updated notes in here so what happening here is just that we updated something in the database we got the new object from uh the database we removed that uh node from a local cache and then we added it in there okay added it back that's the updated node all right all right great stuff that's for update notes and then what we need is as the captioning case is get or create user in node service so um this is a function that we're going to actually use in the next chapter um so how is this function useful this is the first time we're actually seeing the the um signature for this function as the name in the case it says get or create user you see when you at the moment go into our user interface let's go to the login view for instance login view here i'm gonna remove the explorer so you see the code in its entirety and right here when we do auth service firebase login then we get the current user if the email is verified is that we're going to nodes routes now let's then go to our notes view you can see right now notes view the only thing it's doing is that it's creating an app bar with a um sorry it's creating a scaffold with an app bar that we have our logout button in and let's go actually let me bring up scr cpy so i'm gonna use my email address in the login screen so um i actually may need to go and connect this device to wi-fi so boom i'm gonna open up um that login with my user so i'm to get rid of all those i'm going to login in here use oops uh we've sent you an email verification okay maybe i should actually log in with the user who has already been verified so let's log in with this user you see in the main ui of the application um of our application we have this hello world right there because um you can see the body of the the body of our notes view right now it just says hello world so you could pretty much say that the notes view has literally no contact at the moment with the notes service but we're gonna fix this soon by first making sure that the note service allows the user interface to create a new user upon going to the screen so when we come to the screen we need to make sure that there is a user associated with the current firebase user inside our database okay so that's what we need this little uh good function called get or create user which returns a database user in our notes service so we're gonna use that in the next chapter so remember that okay but we need to create the function at this right now all right let's go then and create this function as the name indicates so future and database user and we're going to say get or create user and it has a required parameter i can see required stream email and it's an async function right so um we need to basically have a look at this how we can create this user so the goal in here is to first we try to get this user from the database if that user doesn't exist then we're going to create that user and then in both cases we're going to return either the fetched or the created user back to the caller so let's go in here and just say final user is await get user okay and you see the email just fits in there perfectly but if you remember from the implementation of get user let's go in there and expand this if the user couldn't be found then it throws an error says could not find user that's rq so that if that function throws that error then we're going to create that user so if that user doesn't exist in the database it needs to be created so let's put a try statement in here and then we're going to say on could not find user so here is the user so in this case in the try statement it means that we could get the user okay so if we get to this return statement it means that get user function didn't throw any exceptions such as could not find user in the case that we could not find user we're going to actually create a user so let's just say created user is a way to create user with that email and then we're gonna say return created user and if you look at the create user function as well right here it also i believe does it throw yes so if it couldn't create that user it if it's the result was empty it just says user oh no that's that's where we get the user sorry about that we need to have a look at this insert so yeah that's the only thing it's doing so it's not basically throwing any other error okay the only thing it does is if you're creating a user that already exists i'm going to draw an error so here we have where and we've ended up with a try and catch block that could also throw an exception which we haven't handled all right so what you could do is just to do a whole catch in here and then don't do anything with it i like this pattern quite a lot in my code at least because if i don't do this then i don't actually have the possibility to debug my application later so i can't put like a breakpoint in here and see did any other exception arise if you don't do that because then the exception will be thrown to the caller and the caller will have to handle that but in this case we're not really handling the exception we're just catching it and then we're throwing it back to the call side this only allows you basically to put a breakpoint in here if you want to debug your application later okay so it's just a it's just in quite a cheap way of making your code easier to debug all right for those of you who are interested in this all right fantastic and we've covered a lot and there's still a lot to do but we've come far so congratulations um let's have a look here it says let's get ready for the next chapter and upon logging in we need to call our get or create user function and have the user ready and this is what i mentioned to you before inside our notes view at the moment we don't have any functionality that creates a new user or gets the current user based on their email if they already exist in the database and that is going to be like the actual uh first bit of logic which we're gonna do in the next chapter which integrates our notes view with the note server so the tempo of our course right now is gonna shift towards more and more to the notes view until we have a list of notes and allow the user to create notes update notes so it's exciting times we've come far we've done quite a lot of work up up to this point um and there's still a lot left but um hopefully you're getting the attack at that like the tempo of the uh of the course better and better and you can see why we are doing things the way we are doing so uh congratulations again and uh get some refreshments if you want to again coffee tea and i'll see you in the next chapter hello everyone and welcome to chapter 29 of this flutter course in the previous chapter as you saw we worked with our note servers and we talked about streams and stream controllers we have put uh you know a lot of effort in our note service in order to talk with the database and kind of read from the database and cache the red information in our notes uh member variable so if you haven't watched the previous chapter i highly suggest that you do that because moving forward with this course without having watched his chapters chronologically makes it quite difficult for you to proceed so i'm gonna build on top of the previous chapter as we've done with the other chapters as well and in this chapter we're gonna basically start putting in place uh all the structure necessary in in order for us to be able to display all the user generated notes in the notes view okay so as you can see we have almost everything in place um there are a few functions left to do and we also in this video in this chapter we're going to talk about future builder and also a stream builder and i don't think we've talked about stream builder before we talked about future builder so that's going to be an exciting um new thing to talk about in this chapter all right so i've just i've talked about this in the um in the outro to the previous chapter that what we need to do in this chapter right now in chapter 29 is to allow the user to to go to the notes view and upon going to the note c we're all always going to make sure that that user exists in our database now you see we have firebase right here and then our user has upon coming to the notes view that user must have logged in with a verified email address so that user exists we know that that user exists in firebase and has a verified email address but that user might not exist in our database remember we're gonna store the user generated notes in our database and hook them to the user who created those notes okay so um so upon going to the notes view we always need to make sure that that user exists in the database and the way to do that if you remember let me just bring the code you don't have to try to remember that so let's go into our notes service you can see we have a function called get all notes and but we don't have any functionality at the moment to for instance give us the notes for a a specific user so if we want to do that if you want to for instance get grab all the notes for a specific user then we're going to go with a user's email address because if you look at the way our application is working with um the current user you can see we're working always with officer so we're not going through um firebase directly and our auth service also has an off user so let's have a look at our auth and have a look at auth user and you'll see that our auth user only has one flag that just says is email verified so how do we go and call this function which is called get or create user on our note service where we don't actually have an email address for our current user and that's what we need to do we need to go ahead and add an email field to our off user and so as the caption indicates here we need to add this field to our off user okay so i'm going to change the screen layout a little bit so you see better and let's go ahead and add a new field in there i'm going to have a look at my notes also um or user so and add a new field in here and we just call it the final string um email just like that and get help from your editor in order to add the email field add final field here so this is also going to be a required parameter like this and i'm just going to make it required like this and it come at the end to get the formatting done and here where we actually creating our instance of auth user what we're going to do is to say we return an auth user and the email is already actually in the firebase user let's go to the firebase user and look for email you see there is a getter called email okay and the thing is that this email getter is optional string so what we need to do is just to make it optional maybe in our off user as well okay so in here then where we create the off user we're just going to say the email field is equal to user email and put a comma at the end here and a comma here as well to get the format going so all we did in here would say that our r auth user has an optional string as its email and that email string is read from the firebase user that's all nothing complicated all right okay what we need to do then is to as the caption indicates go to our notes view and grab the let's go notes view here and we need to then read the current user's email address okay so what we're gonna do is saying that our auth user has an optional email but we we as an application developer are sure that because we're using email and password registration we are sure that any user who ends up in the notes view has an email address okay so that's an assumption we're going to make although our off user which was let's see if we can find it off user here although the off user says that i optionally have an email but we're always going to say no that email should exist because we're only at the moment using email password sign in method all right so in order for this notes view to be able to make a call to the notes service and grab or sorry to create or get the current user it needs an email so let's go ahead and expose a functionality in our notes view as the caption indicates that grabs the user's email so let's go in here and i'm going to go to my notes view as well in my notes all right and what we're going to do in there is just to expose the user email so let's just say string get user email let's get rid of this side explorer as well and i'm going to say off service firebase all right off service i don't think it's imported so let's actually see is it imported off service yeah it is imported okay that's good about firebase and this can't be equal so that's why it's going a little bit crazy firebase and then we're going to say current user and you see this current user is now optional but since we are the application developer and we're sure that if you end up in the notes view then you should have a current user that's what we've already made sure in the previous steps okay so if you look at the login screen for instance in our login view so i open the login view here we're saying if the current user exists and is email verified is true then go to the notes view so then we can be sure that inside the notes view we already have a user okay so this current user in firebase currently says optional but we're gonna unwrap it force on rapid okay and then we're gonna say email and force unwrap that too all right so um that's what we've done so now we get the user's email now if you remember inside our um inside our note service we have two really important functions which at the moment are at the bottom of this class which are called open and close respectively and what we need to make sure is that upon going to notes view that our database is actually open so we cannot continue to read stuff from various parts of our database if the database handle hasn't actually be created so let's then go to our uh notes view and in here as you can see this is the reason we made this and notes view a stateful widget in that we need to now hook into the two life cycle events of our notes you and to open our database upon the creation of this node 2 and then close the database upon it being disposed so as the caption indicates let's go and overwrite the init state function in here okay and what we're going to do in here we're going to say uh now we want to basically have a notes service in our init state and we also need to make sure that it is open so so let's have a look uh let me have a look in my notes as well all right so uh we need to open the database in there so let's go and grab a hold of our notes service so we don't have a note service right now but we're going to create that so let's just say late final notes so this is our uh notes view uh undefined class notes service haven't we imported note service and we haven't so let's just do it on import right now so this is our notes view grabbing hold of an instance of node server so that it can work with it okay so um let's go ahead and do that then so we're going to go and say notes service is equal to an instance of nodes service like this and then we're going to say nodeservice.open and right now this function is a future void and you may not really be able to do an async in your init stating here but we're just for now we're just saying open all right so open the database and that's all we have to do and then we have to take care of closing the database so let's go ahead and say upon disposing upon this uh notes views disposal we're also going to close the database because we're good citizens of the dart lab so we're not just going to leave the database open so node service and we're going to say close all right and that's that's pretty much it that's all we have to do for now okay great stuff let's save this and um i'm also going to maybe bring a crcpy here and what i'm gonna do then is to do a hot restart and let's just log out and then i'm gonna log in with that user again if i can spell pick solitude um foo barb has horrible password i've mentioned this before authentication error foo barbaz it could be because this uh phone doesn't have wi-fi right now so let's go in here turn wi-fi on and then i'm gonna go back here android phones usually initial initialize their wi-fi site quite fast so now we should be able to say login and we end up in the main ui of the application so this open function has gone well and i can see that we haven't had any exceptions thrown in the debug console so that was open and close so so let's have a look in here um as you can see in the caption uh right now we are what we're doing is that we're like issuing different functional functions in our for instance let's have a look at delete user what it does is that it says get database or throw um and at the moment this get database or throw only thing it does is just make sure that this db is available in there but it doesn't make sure that that database is open as such it just makes sure that there is a database instance in the the internet in the node service so what we need to make sure now is that every function that works with our database first ensures that the database not only is instance is there but that the database also open all right because if you look at the excuse me um here we have the open database and that basically sets the instance to that database all right so what we need to do is to create a little function that says ensure database and what is it called ensure db is open so uh i'm just going to go ahead and have a look at my notes for ensure dbs open and um let's have a look at putting that maybe above open in here okay so if you're following along with me you just go to top of the open function and we're just gonna say future void ensure db is open and that's an async function all right so what then we're going to do is just to say um let's see we're going to put a try block in here and let's go we see that our open function at the moment throws an exception that says database already open exception so what we need to make sure is that we cache that exception so when our uh our uh notes view gets hot reloaded then it shouldn't try to open the database over and over again and if it does then this open function is going to throw an exception and um and our ensure dbs open function is going to catch that and it's just going to let it go all right so all it does is that we just ensure that we're not opening the database over and over again because it's just an overhead okay so what we're going to do then is we're going to say awaits open in here and in here we say we're catching database already open exception and we're just going to let it go in this case so we just say sorry on all right so now we have this intro db function is open uh it's your db is open function and we need to start using that um so let me bring up the right caption so we need to start using ensure dbs open function in various functionalities in our application so let's first go to delete user here and uh we're just going to say await ensure db is open that's the first place and let's go to create user um we have a function called create user here and we're gonna wait on ensure db is open okay that was create user now let's go to getuser this function get user right here if i can go to it for some reason i'm not able to go to it here and let's say wait db is over uh that that that's that part let's go to get all notes function get all notes and do the same thing await on make sure db is open oh also i can see i didn't actually call the function so let's make sure that i've done it in the other places i'm just going to copy that code and ensure bb is open let's just make sure that i'm actually calling the function and like i'm not like placing it just there so it looks fine all right and so you have to do it in get all nodes function as well and we're going to go to create node and do the same thing so let's just go and await on actually paste that code in there wait ensure db is open and we're we need to do it in um so we not we've done it in create node and let's go ahead to delete node delete node and paste the function right there as well sorry paste the invocation of the function delete all nodes as well delete all nodes right there do the same thing and also we do it in gets note here the same thing and also we have what else do we have um update notes right there and we do it as the first call but and then uh where else do we have to do it let's see we've done it now delete user yeah i think now we place the ensure dbs open all those calls all right okay that was a lot of information um so what we need to do now is to make sure basically that we work on our notes view as we promised in the beginning of this chapter now you see the reason that we created the ensure db is open is that before any of these functions are called that our code is actually going to open the database for us that means in our notes view we don't actually have to do this anymore because we know that by issuing any database related commands to our nodes service that that function in itself is going to open the database for us it's just a nice little feature in our node servers to make sure that we don't have to make an extra call to open the database um before we start using our node service okay so it's just like a convenient a little function all right as the captioning case now i'm going to talk about future builder and async snapshot well um we've talked actually previously a little bit about future builders before but uh what a future builder is maybe actually you should write it here future builder and then go to the code so you see it a little bit better you can see it is a stateful widget so and what it does is that it subscribes to a future that will return its value in the future if you're familiar with javascript then you'll know it as promises um and uh if you're familiar with rx swift or any rx related then you'll know probably as like a single or an observable kind of actually not an observable because that's a stream builder a future builder is kind of like a single builder meaning that a value that starts someplace and then calculates something returns its value and then it finishes that's it so a future builder allows you to submit a future and it will allow you to submit a builder meaning that it takes that chunk of code that produces a value as a future it says okay now it's mine i will take it subscribe to it as the value of this future changes i will give you the ability to return various widgets that need to be displayed on the screen so it basically ties your future logic with your ui logic so it's absolutely beautiful so what we need to do now is to make sure that upon going to our build function right there in the body you see in the body of our notes view here we need to make sure that we are creating a user or getting the current user from the database if it already exists and we're creating that user if that user doesn't exist and if you remember we have this function already it is called gets or creates something something a get or a create user and it's a future so we're going to create a future builder in our uh notes view that subscribes itself to the value that is returned by this and then it will tell us about various updates and these various updates are going to be provided to us as something called an async snapshot an async snapshot is basically as its name indicates is a wrapper as a snapshot around an asynchronous functionality which is in this case our future of get or create user so that's what we're going to do in our notes view as you can see in the caption we're going to now return a future builder in nodesview. and actually that should say notes view notes underscore view so i'm going to fix the caption as well so i don't confuse anybody including myself and notes view here so now it's better i apologize for that so right now we have this hello world but we're gonna change that so it returns a notes view so i'm gonna say sorry a future builder so let's say we now return a future builder and now it says okay there are two parameters that we have to provide one is the future the other one is actually the builder function so the builder sorry the future in itself is going to be you see the future is our note service get or create the user and the email if you remember is the current user's email address which we created a getter for called user email so let's go put that in there user email and then you can see it's still complaining saying that the builder function hasn't been provided so let's go and say then that we have a builder function and right there and i talked about async snapshot because that's the parameter that you get in here is this is async snap snapshot of object right now but we're gonna fix that so um let's then in here um let's then talk about actually this functionality right here so after we get the current user or creates a new user if that user hasn't existed in our database we also need to grab all the nodes for that user and we don't right now have the functionality to have like a stream of all the nodes for the current user we're going to add that soon but as you can see in the caching is we can achieve this with our stream controller which we've already placed like the groundwork for in our node service so let's go and create a little functionality in here in our notes service dot dart and as you can see it allows you to retrieve all the notes so we're just going to say stream of a list of database notes database notes like that and we it's a getter and we call it all notes okay and what it does is is in itself is gonna subscribe to this note stream controller and retrieve all the notes from that controller because remember this note stream controller in it in itself contains this guy all right so and that's what we're going to do we're going to say it returns the node stream controller stream actually another stream get all not so sorry that was wrong and stream all right so that's our getter for getting all the notes um now what we need to do now that we've created our uh so back into back in note2.dart now that we have created our user what we need to make sure of is that if the user could be created then we are going to work with something called a stream builder that retrieves all the nodes from the node service and then renders them on the screen okay but we can't yet render them we don't have any user generated content and we also don't know yet how to render them so first let's take care of something in here this snapshot in here what we need to do is to say if snapchat connection state is connection state dot done like this um if that's the case then we're gonna do some logic in here so let's just say return a text of hello for now okay actually we need to maybe switch this so let's just say switch snapshot dots connection state and i really like to get uh visual studio code to complete the rest for me so i don't like to write all the cases so i'm just gonna say command dot or on mac or control dot on linux and windows i say add missing case clauses and in the case of done i'm just going to say return this text okay if the creation or the retrieval of the current user was completed then just return this text hello and in any other case for instance in the case of default we're just going to return a circular progress indicator just like that okay then i'm gonna put the case of done above that like that all right let's then do a hot restart and i can see my um scrcpy kind of just crashed so yeah stuff like that happens sometimes and that's okay let me go ahead and go back to this shell and say hcr cpy the application is working fine it's just that scr cpy crest so i'm just gonna say your notes will appear here now command s actually my debug process has crashed as well so i'm going to run the application now again hopefully this gradle task goes fast because we've already compiled the application from before so what we need to do you see we are now taking care of making sure that the user is created in the database if it didn't exist or we're getting the user if that user exists in the database but what we also need to do is to start listening to changes to this stream which is in our note service called all nodes and depending on the state of that stream then we're going to build our user interface all right so in this in here we're actually not going to return like a text of hey your notes will appear here but we're actually going to use a stream builder which is very similar to a future builder but it actually listens to changes to a stream okay so oops did i just kill the application right here so there we go your notes will appear here so that seems to be working fine so let's go in here and then say that we want to um return our stream builder i'm going to put this back and before we do that i want to explain this little thing that i've shown in the captions what are the waiting and dawn flags in the connection state you see both a stream builder and a future builder work with something called an async snapshot which is this guy you see async snapshot and this async snapshot can have various connection states so if you go to connection state in there and you can see we have none waiting active done all right so when you when you have you see in the case of an active says for example a stream that has returned at least one value but is not yet done so that's for a that's for a stream uh but if you're waiting for a future or a stream then you're gonna get this waiting flag and it done is gonna happen for your um a future so a future that has completed its task as i said it does something and it completes but a stream usually it just keeps living so you can't like hook into or you shouldn't hook into the done event for a stream but you should actually hook into your waiting um connection state so that's what we're going to do so connections stay done for a future and a connection state of um are waiting for the stream so in here let's then create a stream builder and our stream is going to be our note services all notes um so that's the stream itself and then we need a builder and let's get visual studio to complete that for us um okay and in the builder what we're gonna do is we're gonna say switch snapshot connection state like this get visual studio code to complete the rest for you in the case of waiting we're just going to say return paused text waiting for all notes okay i'm going to remove the break from here and in any other case so in the case of default we're just going to say return on circular progress indicator just like that so now you see if i command s to hot reload then it just says waiting for all nodes to appear on the screen so this is now like the skeleton of our application's notes view so that it takes care of two things it gets the current user using his or her email address if that user already exists in the database or creates it so that's the future builder and the the widget returned by the future builder in itself is a stream builder so the stream builder then calculates all the nodes and returns them from the node service and then it has a connection state and waiting which in turn right now is saying waiting for all nodes and we're going to change this later so that so that uh it doesn't just return a text it actually returns a list of notes all right so now let's talk about something else before we wrap up this chapter and you see at the moment what we're doing is that we're saying our note service um is a new service right here so every time go into init states if i command s in here or if you did a hot reload or hot restarting here actually hot restart this i can see maybe that is the reason we're crashing the entire application because we're creating a new node service so that could be the reason i can see hot restart is a little bit flaky right now so um so that is pretty much the reason we're going to create a single now if you're not familiar with what a singleton is a singleton essentially is a pattern used in software development where you create a service for instance or a class instance where that class instance is only one inside the entire application right now any place in our app we can go and create a new instance of node service but if you think about it the node service should only exist as one copy in the entire application it shouldn't be like made new copies of this note service over and over again so that's what a singleton is and that's what we're going to do with our note service so i see i have a little bit of problem with my um captions and i'm going to bring the next captioner and fix that so let's go ahead first and uh before i run the application maybe we should fix this problem with our singleton so let's go to our note service and we're going to create a single now singleton pattern in various languages i mean it differs from language language and dart is not as clean to be honest with you in my opinion as it should be such as it is in languages such as swift um but it is what it is and we need to kind of live with it the way uh it works right now so the way that we do it uh that we make our class note service a singleton is to go ahead and first create a private constructor for our class so we're going to say note service underscore and just a shared instance and this is just a function name it's just a private initializer to this class okay and what we're going to do then is we're going to say static final notes service so we're creating a shared instance and we're going to say notes service got shared instance so this creates that shared instance for us but no one from the outside world is going to be able to then make a call to these two because they are well private so now we're going to create a factory constructor we're going to call it note service like that and that is going to return a shared instance for us so it's just a hack to be honest with you in my opinion at least it's it's a hacky way of creating a singleton but that's the way it works in dart at least for now all right now we've created our singleton so what we can do then is i mean we don't have to make any changes to this guy to the init state because right now it's making any it's constructing node service and we have changed that so that anyone who calls node service like this is actually coming to the factory constructor which then in turns returns this shared instance which in turn calls this private factory and it causes private initializer or constructor so it's like a three layer deep in order to create a singleton all right well done we i mean we could also try to run the application while all this is going on and i can bring up scr cpy again and if it's doing any better bring it up here okay so we've done quite a lot of work we've laid the groundwork for the next chapter so now we have the ability to hook into all the notes available in our database which is being controlled by a stream and a stream controller and we're then being able then we're able to display those notes on the screen use using this stream builder which i'm trying to find right now which is right here okay so we've done quite a lot of work and well done to you for sticking with me throughout this chapter as is the tradition we are doing in every other chapter by the end of chapter we commit our work and also tag them so let's go ahead and do that i'm going to change the screen layout a little bit get rid of the cr cpy it has been a little bit angry with us today this scr cpy and here's the screen layout and i'm going to increase the font size of it and a new shell all right so in the previous chapter we uh committed and tagged our work as a step 11 i believe so if you say git tag you can see we have up to step 11. let's go ahead and say git status first yep some files that have been modified and we add all the files and then we say step 12 this time and we push our changes and then we're going to tag our work as well as step 12 and then we push our attacks fantastic well done now again uh what we do in the end of every chapter is we talked a little bit about what we're gonna talk about in the next chapter and as the caption indicates we're gonna uh we're done with the basics of the notes but we have no data and that's what we're gonna fix a remedy in the next chapter so we're gonna talk about how we allow the user to press a button for instance in order to create a new note and for that note then to appear in our stream builder and display to the user so maybe you want to take a little break some refreshments do that please and i'll see you in the next chapter hello everyone and welcome to chapter 30 of this flutter course in the previous chapters we've been working quite a lot with our database layer and we've also been working with the ui in order to kind of make sure that we can have a list of notes um but as you've seen in the previous chapters we don't have notes or we don't actually have the ability for the user to create these notes so starting from this chapter we're going to start working on creating some sort of user interface in which the user can enter their notes and those notes will be saved then with our quad servers that we've created in one of the previous chapters before we carry on let's take care of one thing at the moment our notes view doesn't really have like the proper title i'm going to bring the code here on the screen so you see it as well and i'm going to bring scrcpy you may have your simulator or emulator um or an actual device on the screen so that's also fine let's do some rearrangement here and i'm also going to rearrange the screen here so you see the code better at the moment the ui and the title of our main ui is just saying main ui so let's take care of that and that's inside notes view dart let's find where we're creating the app bar and here we're saying main ui so as the caption indicates we're gonna change that to your notes like this and command s hot reload and then we can see your notes appear there so that part is now done um so let's now have a look at how we're gonna enable a user to create new notes in our application you see um there are different ways of going about doing that there are like some applications that will display something called a floating action button a floating action button is a button that appears usually to the bottom right of the screen if you have languages which are left to right or if you have arabic lang like arabic persian language like that that you write from right to left then that floating action button should appear on bottom left so it's kind of like a button that appears just floating on the screen um and usually it's like out of uh out of your um out of the way for your main ui uh however it can get sometimes in the middle of the way so um for instance if you have a list of notes and these notes can like their titles can go to a few lines of text and then you have a floating button that sits like at the bottom of the screen it could just block some again parts of your content so some people don't like floating action buttons and floating bar action buttons are usually they usually appear in android applications is i think it's it's coming from material design from google i could be wrong about this but usually you don't see them in ios applications and since we're developing our application to be user friendly for both ios and android users we're not going to use floating action buttons for now but there's just to be clear there's really nothing wrong with floating action buttons so so what we could do is either we could go in our menu here where we have log out and create a new item in here that says for instance a plus or add add a new note or something like that i'm sorry i'll just add this also to uh do not disturb so we could either add an item in here that says add note something like that or we could go to this bar that we have up here our app bar and add a new item just like we have this three vertical dots we could add a new item in there so now then it comes to kind of like preference and some sort of reasoning of why we should add the plus button the way we're gonna add it and my reasoning behind um wanting to put the plus button but like beside this these vertical three dots is that adding a new note is pretty much like one of the main tasks users would want to do in your application's main user interface so they either go in here to and delete their notes update their notes or add a new note so there are three things they're going to do deleting notes is usually not that common so updating notes and adding new notes should be like the main actions that your users perform in your main uh application ui so it should be very instantaneous it should just be very easy for users to do that so if you put a plus button here beside this these three vertical dots then it takes the user just one click to go to the new screen in order to create a new node however if you put like add to notes menu in here then they have to first do one tab to go here and then another tab in order to create to go to the next screen and that's just like one tab extra and that's where we're gonna add a plus button beside these three vertical dots so before we get started with that let's go ahead and do some preparation for that so we need a widget and which is going to be our new notes view and as you can see we're going to create a new file for it inside lib views notes which is a new folder i believe which we haven't had from before let's go in here we have views as you can see and we don't have a folder called notes so in views what we're going to create now is this dart file new node view so i'm just going to right click on it and say here i'm going to say a folder called notes which we don't have yet and i'm going to say new notes view dot dart okay so that's that file already we're not going to do anything in that file yet and now that we have our notes folder under views it just makes sense to move our notes view here as well which is at the moment sitting under views you can see the breadcrumb here says lib views notes view it makes sense now to move this notes view which is the list of our notes into this notes folder as well so i'm going to need you to just drag that file and place it inside the notes folder okay all right that's great excuse me so we've done that now um now what you may have noticed if i bring the list a little bit higher now that we've done that also let's just make sure we haven't broken any uh imports notes view oh i see that's that's really great because by dragging the notes view into the notes folder visual studio was intelligent enough to refactor also all the imports that we're referring to notes view so your editor of choice like if you're using sublime or if you're using some vim for instance it may not be able to automatically take care of that so by you moving your notes view inside the notes folder depending on how you do it you may need to fix your imports as well so if you search for nodesview. let's have a look at i can see the only place it was imported it was the main.dart file so you will you might need to go and fix that import in there okay so if you're getting an error for your imports then you know why all right so that's that's moving our notes you now if you've noticed if you go back to the editor here you'll you probably have noticed that we have some red files in here and it's because we have added um our email uh an email field to our auth user so if you go in here you can see that we added this email field in our auth user in one of the previous chapters because we needed to be able to retrieve nodes for a specific auth user from our node service okay so after adding that now we've broken our tests and we haven't really had the time yet to fix the test so uh let's have a look at how we can fix our test if we if you dr uh scroll down a little bit in our tests file you will notice where we've broken the test and this is here we're in two places where we're creating an off user okay here and the way we're working with this off user in our test is not really something that we're writing tests for later like we're not actually creating an off user and then doing a test against the off users email so it's at the moment it's pretty much just decoration in that we need to just make sure that our tests compile and that we don't have a compilation error here so let's go and see if visual studio code can help us with that so i'm just going to do command dot on mac or control dot on windows and linux and say add required argument eval and for email you could just say fooatbar.com so that doesn't matter so much and a comma at the end to get dark formatter to format the file correctly for us and then excuse me gonna get help from visual studio code again and say add record argument email and again we're going to say um fooatbar.com and a commanding all right so as you can see in the caption also we just need to make sure that we're running our tests and making sure that we haven't broken anything so let's go to our tests in here and see if i if i can bring this up a little bit change the screen layout so you see what i'm doing as well uh increase the size of the screen and i'm going to search for flutter test and that's the line the command that you also have to type as the caption at the bottom of the screen indicates as well and let's just run our tests and see what we get for results if we've done everything correctly we shouldn't have any problems with our tests at the moment but you may have like diverged from the course uh for a good reason and written more tests and you may then have to fix those tests as well and i highly encourage all my watchers whoever's watching this course to actually do as many tests as possible experiment with widget test integration tests and unit tests as much as you can to learn how that works um all right so that's that now let's go ahead and change the screen layout we've taken care of our tests now and you can see the tests have passed and also we don't have any more red flags inside our auth test.dart file all right so what we need to do now you see when we then add a plus button to our main ui in order to go to our new view which is um i believe we created it here new note view we need to define a round for it we've already done that for um for all our other routes so if we have a look at our um let's see if we can find it constants routes we have verified email routes we have nodes route register route and all of those so i'm just going to have a look at my notes and make sure that we define our new route in here excuse me so let's go and call this new route and we're going to call it new note route and we're just going to say slash and notes slash new note all right so and remember this doesn't really mean anything except for excuse me again except for you to handle like your route name so if you had like notes with a z it would also work as long as you're using the same route name everywhere so don't think that this is like bound to any sort of a magical file finding a mechanism in flutter it has nothing to do with that it's just for you to define your route name so you could literally just say fu in here and as long as you use this route name everywhere everything's just gonna work as expected so that's our new note route created inside the cons of routes dart as the notes indicate as the caption on the screen indicates we have to go to main dart file in here and we need to then go and define that route uh here okay so we have login route register route notes route verify email route and then we have to define this new route which is called new node route okay so let's just let's just say new node route it takes a build context in here we could just ignore that with an underscore if you want to i'm not doing that and then we're going to create a new instance of new uh node routes sorry a new node view um but we don't have that yet so let's go and define the new node view but for now i'm just going to say const new node view like this and this is not going to work because we don't have that view set up yet we've just created the file for it okay so i'm going to close some files which we don't need and let's go into our new note view and as the caption indicates we're going to create a stateful widget called new note view so i'm going to use a flutter sorry visual studio codes and stateful widget template here stf and i'm going to call it new notes view right and we're going to get some errors and you know already that's because we have an imported material dot dart so i'm going to get help from visual studio code command dot on mac or control dot on linux and windows and say import material and all those errors are going to go away okay so now we have our new node view excuse me so let's then inside this new note view go creates a simple scaffold so i'm going to say we have a scaffold and inside our scaffold we have an app bar and we're going to say avbar and an app bar has a title and in here we're just going to say cons text new note something like this and for the body of this scaffold we're just gonna add a const of text that says write your new note here something like this okay so this is a very simple stateful widget at the moment i mean it's not even stateful it and what it's doing right now is it could pretty much be achieved with a stateless widget but in the in the next chapters we're going to add more and more logic to this view so it needs to be a stateful widget for it to be able to work in the future as well and for what we have planned for it okay excuse me so now that we have this ma new note view let's go ahead in here back to our main dart and get help from visual studio code to import that file for us so i'm just gonna say import and you'll see it will be a new import right here on line five for me maybe another line for you so let's import a new node view and it allows us to basically define a route i'm just to say command s and just to be sure since actually not to be sure we are we are 100 certain that the changes in our main um function won't be won't be taken uh into consideration when we do a hot reload we have to do hot restart for these changes to take effect so let's do a hot restart here okay and for some reason i can actually see my scr cpy has now crashed again it's a bit flaky that's okay i i'm not gonna complain uh it's just an open source project to be honest with you and i can see i actually have lost my connection from flutter as well to the program so let me run that code now in scrcpy on my actual android phone and i'm also going to ensure that my android phone actually has wi-fi as well so turn wi-fi on on my phone and i'm going to go back here to the main interface so while this is all compiling let's go to the next step that we have to take care of which is actually displaying oops so which is actually displaying um this new note view all right as a caption indicates we need to go to the notes view and on press of the icon button show the new notes view so i'm going to go to my notes as well go to notes here and we have to add a little button on our uh notes view so let's go ahead and go there we'll have a look at how our note2 is structured at the moment as you can see right now we have an array of actions which just for now it has a pop-up menu button excuse me and we need to add a new icon button in there so let's go ahead and say icon button an icon button has to have an icon and an on press so let's say unpressed so remember this is going to be our plus icon all right so that's our on press and for the icon we're just going to say const icon and then we're going to say icons add and as you can see i believe that your studio code was able to show your icons right in line as well so you can see here that's how the button is going to look like which is a plus button all right and a comma here to get that working so if i do command s in here now we should see a plus button after hot reload all right so but that button isn't doing anything because it's unpressed it's empty all right so what we need to do is just to say uh navigator of our context or build context and we're just going to push a route called new node routes that's it all right so that's all you have to add a comma here just to get the code formatting working all right so let's let's actually test this and see if it works so i'm going to press the plus button in here and you can see our new node route is being displayed on the screen with the little text that we added here that says write your new node here right and pressing the back button will then send us back to the main ui of the application and you may have noticed that in the notes view i didn't say push name and remove until and that's because when you press the plus button in order to create a new note you want the user to be able to get back to the main ui of the application whenever they need to and that's what is facility facilitating this back button right here okay all right that was great stuff and that is pretty much all we had to do for this chapter so a short chapter is kind of refreshing to be honest with you if you ask me so that's really good um as is tradition let's commit our work so that we can get ready for the next chapter i'm gonna change the screen layout here a little bit oops um let's go in here change the screen layout and let me bring up the terminal and increase the size of the screen so i see it better so we're going to have a look at our git status and i can see there's a whole new folder in here called lib views notes and we have two files under there which is our notes view and new notes view so let's just say git at all and have a look at our status here you can see now everything's mentioned there i'm going to get rid of this make it a little bit bigger so you see better so what we need to do is just to commit this first and we're going to say step 13. i believe so at least so let's have a look at our logs yeah step 12 was the last chapter so we're going to say um step 13 and i'm gonna push now our commits to github and then we're going to say good tag step 13 as well and with push tags all right so that's for our tagging as well so if i say tag now we can see all the tags that we've created so far 13 of them all right so that's pretty much what we had to do and now as again is a tradition for every chapter of this flood of course i usually talk about what we need to do in the next chapter so we can get right get ready for that chapter as well in the next chapter now that we have our new note view we are going to work with adding the logic to new note view so that we can actually insert new notes into our database so that we can start manipulating those notes so next chapter is going to be a bit of a heavy chapter code wise there is a lot of code so if you want to grab some refreshments be my guest please go ahead and do that and i'll see you in the next chapter hello everyone and welcome to chapter 31 of this flutter course in the previous chapter we did some preparation work in order to create our new note view and we've tagged everything everything is ready it's just that we created our new note view as a stateful widget which has pretty much no logic it had a simple scaffold with an app bar and a simple text displayed on the screen so in this chapter we are going to make sure that the user is not only able to go to the new note view or sorry the new note view but also he or she is able to create an actual note and modify its text and then be able to go back to the main user interface so we have quite a lot of work to do these chapters as i mentioned in the previous chapter at the end of the previous chapter this chapter is kind of quite code heavy so uh but i'm gonna make sure to take you through all the code that we're gonna write step by step so you don't miss anything okay um before we get started we need to fix something in our um notes view and that is to ensure that we're listening to both the active state of our all nodes stream plus the waiting and be i mean without us having to actually without me having to explain that in abstract terms let me bring up the code and have a look at what we've done um and how we can make it better so let me change the screen layout so you see the code better let's go to our notes view in here and you can see at in in the actual body of our notes we have the future builder where we get or create a user with an email address and which you'll soon actually see why we're doing this and also we have this this part which says switch connection state waiting and then in here says waiting for all notes the plan for us is to in the future soon actually in the near future to display all the notes that the user has created in this user interface however right now we're only listening for the connection state waiting and if you look at the document documentation for waiting it says connected to an asynchronous computation i'm waiting interaction however if you look at the active it says connected to an active asynchronous computation that ha and that stream has returned at least one value so now we have if you look at our stream is a stream of all notes so this all notes can either be empty in the beginning or it could contain some notes let's go with the stream being empty when the stream is empty meaning that the user hasn't created any notes yet that have been populated in a note service then the connection state of that stream will be waiting because dart is now waiting for that stream to return the first value so that's great and we're saying okay if that's the case then return this but as soon as the stream contains one value or as soon as the stream actually returns one value then its connection state is going to be active and what we've done is just we waited for waiting state but as soon as it goes to active then we're showing a circular progress indicator and that's not the not not the right logic so we need to fix that so let's go to our notes view and right after this waiting we're also going to say case connection states dot active all right so this writing two cases right after each other it's an implicit fall through as i like to call it some language is called a follow-through for instance swift meaning that a case has no logic and is literally falling through to the next case so you don't have any break statements here in here okay so this is a follow through implicit fall through and meaning that in both waiting and active states then we're showing this text and if you command s then you're not going to see any difference in the running of your application it's just that we fixed a broken logic all right all right now to the exciting parts and i'm gonna bring new notes view to here just gonna reorganize it you don't have to do that but you need to now go to your new node view dart file because this is where we're gonna work on for pretty much the majority of this chapter now okay so what we're going to do in this new note view upon coming to the screen we are actually going to create a new note for you okay and we're going to keep hold of that new note and creating a new node if you remember from our node service if you go our utilities we have crowd here and we have node service and then we have a lot of functions in here at least let's see if we can find the create node view sorry the create node function here you can see it's a future so we cannot immediately get get a result from this create new node so the goal for our new node view here is to use future builder inside the body of this function so inside the body of this function we're going to say as soon as this new node view state has been created then it also needs to create a new node in the database however remember with flutter we have hot reload meaning that as you're on that view and you're editing your text and blah blah you may change your code a little bit and then press command s pressing command s is just going to call your build function again so if you then inside your build functions um scaffold body and you have a future builder which in turn creates a new note that function is gonna go gonna get called again meaning that every time you do hot reload while you're on that view a new note is going to be created and for that we as the caption indicates we need to keep hold of a variable called notes so that we don't recreate it every time the build function gets called alright so let's go ahead and do that so in inside the state of your new notes view let's go and define and say database notes and we're just going to say notes like that okay also we just make it optional because it has no value to start with okay and what also what we also need is to keep hold of our note service um and as you saw in the previous chapters we created node server as a singleton but also you'd be really good if you didn't have to call this a factory uh function for the singleton over and over again whenever we're working with node servers so we're gonna also keep hold of our node service as a late final variable here so let's just say late final and we're going to say this is endnote service now first like this all right and um you haven't seen maybe the ui of the application but while we're working on variables to keep hold of we also need to keep hold of a text editing controller now the way the ui of this view is going to work here is that instead of this text in here we're going to create a text field which will vertically increase the size as the user keeps typing their information or their notes in that field so what we're going to do is to keep track of the text that the user enters and when the user is entering new text we will automatically sync that information with our database and in the future when we go to firebase we're going to sync that information with firebase so we need a text editing controller to keep track of the text changes all right so um let me then bring this caption in here and let's then go ahead and do as the caption says let's say late final and text i think controller these documentation sometimes are just excessive i believe and we call it text controller okay all right um that was great so what we need to do now um is to facilitate our uh i mean we haven't really initialized any of these but we're going to take care of that soon so where we haven't forgotten about that but what we need now as i mentioned in the beginning of this chapter when we come to this screen we're going to create a new note and we need to have a function for it as the caption in the case it's going to be called create new note and it's an asynchronous function and we'll see soon why so let's go ahead and say future at database node because it creates a node with our node service and we're going to call it create new node and it's an asynchronous function so in this function what we're going to do first is just to see have we created this note before inside this node variable if we have created this node before then we don't have to create it again we just return but if we haven't created it then we go to the node service and say create the node and then get that node back to us all right so let's go ahead and do that let's just say final existing node is equal to this note and then we say um then in here we say if existing note is not null then we just return it this thing notes all right so that's the return statement that means we already have a note and if we don't then we're going to create a new note but remember when we create a new note our um creates new note function on the notes service if you look here create note it requires an owner so now all of a sudden we have to have an owner okay and again remember the notes view upon going to the main ui of the application the notes view creates a new user in the database meaning that you've logged in with firebase then you go to the notes view notes you took care of creating that user all we have to do here is just to retrieve that user so we can actually count with that user already existing inside the database all right so let's just then say final current user is equal to um our auth service firebase and then we're gonna say current user and we're just gonna explicitly um unwrap it meaning that we're expecting a user to be there if you've ended up somehow in this new note view you may be thinking but why that's unsafe well it is unsafe it is it is going to crash the application if the current user doesn't exist however you should never end up in this new node view if you don't have a current user so ending up on this screen and not having a current user is worth the crash because you want your application to crash if you're if what you expect from your applications user interface and logic has not been met by the previous screen so you're now creating an expectation and crashing the application at this point is actually a good thing in my eyes because if the current user doesn't exist you should never end up in this view if you've ended up in this view and you have no current user something is seriously wrong so it's completely safe i would say to explicitly unwrap the current user in here okay and we're gonna extract the email from the current user so we're going to say current user.email and we're going to unwrap that as well because remember email was an optional field but again since we know that our authentication right now is going to take care of the email because all our users register with an email addresses and the password then we can be sure that the email address exists all right so let's go ahead and get that owner from the database so we're going to say the owner is equal to our off our notes service so we're gonna say await notes service and then we're gonna get the user with that email and then we're gonna just return our note service create node so we're going to create a new node in here okay so let's say note service creates notes with that owner and you see this returns um a future of database note which is pretty much what we need to return in here so let's just return a wait on that all right all right fantastic that was for the creation of the new notes and in here you can see that we're not setting this um new notes that we just created to this note variable in there we're going to actually take care of that a little bit later so you don't have to worry about that all right that's for the creation of our notes now what we need to do is when this view is disposed of meaning that for instance the user presses the back button on this view we need to ensure that the current node in the database gets deleted if there is no text entered for for that node so the reason for that is let's say that the user is on the main interface uh of the application right here the user then presses the plus button and then says hmm i actually didn't want to do that so they press the back button if we allow the user to do that and press press the plus button we create a new empty node and go back then the view may just be full of empty nodes so it will just be like empty cells that the user is not even able to see because later as we'll see in the next chapters we're going to populate this list with the actual contents of your notes because our notes don't have titles so the actual text we're going to display is the note itself in here inside various various cells so what we're going to do is saying that if you go and create a new node and you don't enter any text meaning that the text is empty work upon you going out of this screen out of the new note screen we're going to delete that note if it's empty okay so it just makes sense so let's go ahead and create and find that function so i'm going to bring that here and let's just say void delete note if text is empty all right and then we go in here now we have to have a look at our notes and and let's just say we get we get the note so we say in here final note note that should be populated inside of our state and then we say if the text controller's text is empty it's empty and the node is not null then we go to our node service here and then we ask it to delete the nodes right there okay and then we say use notes id like that alright so yeah that should that should be good to go so that's the deletion of the note from the database if the text inside our text editing controller is empty all right so that was for deleting the note if it's empty how about actually saving the notes if it's if there actually is text in it and what we're gonna do in our as you'll see soon inside this view where the user can edit their notes or add new text to the notes we're not going to have any type of save button in modern mobile applications if you're not a software development from before you may not notice but if you're a designer you probably already noticed that in most note-taking applications on mobile devices at least there is no save button all your contents will automatically be saved so that's actually a good design decision usually in most places you don't need a save button usually in mobile applications sorry especially in mobile applications so we're not going to have a save button so we in order to facilitate not having a save button we have to have a functionality that automatically saves the current the current node for instance if the user then goes out of this view so it will automatically be saved okay so let's go ahead and create a function in here as the as the name indicates and it's called save node if text not empty and i'm gonna bring the uh function signature from my node so i don't have to type it manually so you will need to unfortunately type this manually unfortunately unfortunately i don't know but you will need to type in manually save notes if text not empty and what we're going to do in here is very similar to our the code that we wrote for delete node if text empty so first we're going to get the node is node and then we get the text in our text controllers text and then in here um we're gonna say um if the note is not null if note is not normal and um our text is not empty then we're gonna await our note service update notes functionality here and that's exactly what we're doing here so it's very simple we're just saying that if there is text which is is not empty and we have a note then just update that note in the database so very very simple all right two very important functions now we have to put these functions in use as you can see we're getting a warning in here from the analyzer saying that these are two private functions which are not referenced and that's for a good reason because we're going to reference them inside the disposal of our new node view state when this new note view basically is being killed by the system for instance when the user presses the back button okay so let's go into the dispose function and we have to take care of uh three things in here so let's go and say that we have a dispose function in here and that's going to be overwritten by default sorry i'll bring it up here and i'll write it from the beginning so you see this pose okay and it does overwriting for us and what we're going to do is first going to say delete the notes if text is empty then what we're going to do is we're going to say otherwise save the notes if text is not empty and then we're going to get rid of the text controllers and call the dispose on it so as a good citizen of the dart land when you create a new text editing controller which we're soon going to do we also need to make sure that we dispose of it upon this pose all right so um so that was a lot of code and i'm gonna also have a look here i can see i haven't actually provided any captions for us taking care of the init so um let's take care of so i basically what i'm doing right now because i just noticed that i haven't provided a caption for the init function well we're gonna do it right now um because that's a very very important uh basically function that we need to program so uh i apologize for that as well i'm gonna bring it here and then show you the caption so you see what i'm doing so we have this pose but we don't have init state yet and i'm going to put init state in here so uh let's see or do we have any state already i don't see that so and i can see that the visual studio code isn't really helping me with that so i'm just going to say overwrite void init state like that and then we have to call super in its states okay so you may have to type that by hand as well individual studio code was being a little bit angry at me maybe because i just forgot to write the caption for internet state and then in here what we need to do is just to ensure that we're creating both an instance of node service and also our text editing controller okay so i'm just going to say node service and that is equal to node service and that's just a singleton so it's not going to create really a new instance if it already existed from before and our text controller is going to be a new instance of text editing editing controller just like that all right so i'm going to save this and then i'm going to do a hot restart um and scrcpy is a little bit angry these days with me when i do hot restart and i don't really know why but i have learned to live with it so i'm just going to say scr cpy and then i'm going to run the application without debugging and bringing it bring it right there okay while that is doing its job we need to take care of some other functionality you see um when the user is entering text in the main ui of the application so when he or she is entering the text typing on a keyboard we need to make sure that we're constantly updating our notes in the database so we're not gonna leave the updating uh for instance while when the user presses the back button so we're constantly gonna do that as the user is typing um in the on the screen so for that we need some listeners so as the caption indicate as a caption at the bottom of the screen in any case we need a text controller listener and all this text controller listener is going to do is it's going to be a body of function it's going to be a function that takes the current node if it exists then it's going to take the current text editing controllers text and update that notes in the database all right so let's go and create that function so void and we're going to say text controller listener and remember this function is not yet being called it's it's for us then to hook to the text editing controller as a listener so we are soon gonna write another function that says hey text editing controller whenever your text changes call this function all right so don't worry about that it's not being called yet so in here we're basically going to get the note um i'm going to get rid of this as well i'm going to say final um notes is this note and then we're going to say if note is null meaning that we don't have the note then we just return we can't work with null nodes and then we're going to say get the text which is from our text controller like that and then we're just going to await on our note service updates notes with that text and then comma at the end to get the formatting working so that's easy that's very simple doesn't require so much explanation perhaps it's just a simple update note all right perfect so as i mentioned now that we have this text controller listener we also need to have a function that is called setup text controller listener which first removes this listener from our text editing controller if it has already been added and then it adds it again all right so let's go ahead and i'm just going to copy that function name so i don't have to write it again um and then in here we go to our text editing controller which we call text controller and we say remove listener and that listener at the moment for us is called text controller listener okay so and then after removing it we're going to add it so right here i'm going to add listener and just add that listener back in case this function is called multiple times all right so now we're going gonna get to the juicy part of this chapter which is because you see we've already added a lot of coding here but no one's really taking advantage of these so or actually we can't say that because the idiots sorry the disposes for instance taking advantage of save node if not empty and it's taking advantage of delete note if text is empty but we're not taking advantage of this create new node and we're not taking advantage of the setup text controller listener so that's what we're going to do in the body of our um of our uh widget at the moment the body it just says context write your new node in here but what we're going to do is we're going to replace that with our future builder what is this future builder actually going to do remember when you press the plus button on the main ui of the application no one is creating a new note for you you need to do that yourself in this new note view as its name indicates so let's go and replace the body of this function of this parameter with the future builder remember the future builder has to have two variables one is the future itself and the other one is going to be its builder function so for the future we need to call the create new node which returns a future remember it actually returns the database note and we've already coded this function okay so that's the future that is going to be called by the future builder then we're going to write the builder and i'm going to get help from visual studio code to complete this and remember in your builder you have to return a widget so what we're gonna do is since this is a future we need to look for its done state it's not gonna be where we don't have to look for active and waiting we just have to look for done or else we're going to show a progress indicator okay so let's just say switch snapshot state connection state and help from visual studio code to add these missing case clauses for me so um non-waiting so none of these are important except for done right so we're going to leave it like that and then in the case of uh default so we're just going to say default oops return cons circular progress indicator so for now we're saying that when this create new node is finished so a new node has been created in the database we come to done but we're not returning anything and that's the reason you're seeing this little error here but if the connection state is not done for instance if it's waiting for the create node to happen then we're going to show a little circular progress indicator to the user and remember this is going to happen so fast that you're not even going to see this however i'm completely aware that the circular progress indicator may not be the previous solution but what we're going to do here is we're not going to spend so much time on predefining this code since it's gonna probably be displayed to the user on a modern hardware on a modern telephone just for a few milliseconds so it's probably not worth predefining this code so much right now at least okay as we're going on in this course but if you have unlimited amount of time and you and you really are attention and you have a lot of attention to details then you may want to fix this up a little bit and maybe put it in some sort of center or maybe change the color etc etc but we're not gonna do that right now okay remember our future builder at the moment is just creating a future builder and it's and it's understood that it is a database note so if we go upon the don connection state and say snapchat snapshot data and though it says object well we already know that this snapshot data is of type database node as it was the future itself so we're just going to say final actually no we're going to assign that to our nodes variable remember we have this node variable up here and pretty much all those functions are relying on that node variable to be there and that's what we're doing we're creating a future builder that creates the node and then we assign it to our nodes variable okay so we're gonna then say snapshot data adds database nodes so that's how we get our nodes from our snapshot right after doing this we're going to call our setup text controller listener because this is it's at this point that we want to start listening for user text changes on our main ui all right and right at this point we've done what we had to do except for actually return and returning a text field to the user using which he or he can edit the text on the ui so let's let's go ahead and do that so remove the break statement in here because we don't need it anymore we're just going to say return add text field i believe we're going to assign our text our the controller parameter we're going to assign a value of our text controller in here so that's how a text field can send messages to an object called a text editing controller and say hey my text has changed that is our proxy to a text field in flutter okay so that's setting up that and what we need to also do is to allow the user to enter multiple lines of text in this text field because remember text fields usually in flutter are like one line so for instance you're writing an email address or you're writing your password so they're not like multi-line text fields by default unless you make them multi-line so that's what we're going to do now so we're going to say our keyboard type you can see it's of type text input type so then say text input type alt-line all right so that's going to allow you to have a little enter key at the bottom uh right hand side of your keyboard if you're left to right on like english language or if you're right to left language like arabic then that little enter key is going to be at the bottom left so then in here you will get that keyboard as you'll soon see actually and you'll get that key on your keyboard to go to the next line now in flutter as it is also in swift when you're doing ios development there is a weird habit of creating text fields that are multi-line with strange parameters and unfortunately it has leaked to flutter as well in that um you you don't have like a parameter in text field that says multiline so if you want to create a text field that is multi-line and it kind of like expands as you enter more text into it then unfortunately you have to call and you have to assign null to the max line's parameter there are some discussions on github about why that's the case but there's a good reason behind it okay um and what we're then gonna do is if we if we do like this and i press command s and we go here and we press the plus button in here okay you'll see there's a text field in here that's great okay however it's not so obvious the user what what am i supposed to do what is this line here am i gonna tap somewhere here it's not so obvious so what we're gonna do is to add something called a hint to this text field if you're a designer or a developer from before you probably already know what a hint is but if you don't know what a hint is a hint is little um as this name indicates a little text that usually gets displayed to the user telling telling her or him uh what is expected to be entered in this uh field so let's go and add the hint and that is through a property on our text field called decoration and that's uh an input decoration inside our input decoration we're going to add a parameter called hint text and here we're just going to say start typing your notes like this all right so command s and a comma here to prefi the code a little bit but there we go now we have hints in here and as i bring up as i tap on this text field you can see i can start typing in here and press this little button that i was talking about for multi-line and as i start typing more and more then the text field is gonna increase in size all right so that is that is really what we have to do in this chapter i hope i didn't scare you by saying in the beginning of this chapter that this chapter is gonna be kind of code heavy but i mean there were there was quite a lot of code but hopefully you could stick with me throughout the chapter and get it to this point as is the tradition in all the other chapters we worked on we're not gonna lose we don't want to lose the work that we're doing on our code so we need to make sure that we commit and also we tag our code okay so let me change the screen layout a little bit and we've tagged the previous chapter as step 13 so as the caption indicates here we're going to tag and commit this code as step 14 so i'm going to say git status two files change and then i'm gonna add them all to the staging environment and then i'm gonna commit them as step 14 and push my changes to github and then i'm gonna tag our code as step 14 as well and then push our tags okay um so that was that for tagging um now again as is tradition for other chapters as well at the end of every chapter we're going to talk about what we are going to discuss in the chapter that follows so we are now actually creating notes it may not be immediately visible to you but if you if you for instance have created some notes then this screen should be able to render those notes because the new note view is doing everything necessary to not only create the note and let's see where it is here create the new note but it also is updating that note for us so here you can see update note so those notes are in the database it's just that the main ui of the application which is this node c the dark is not able to render them all it's doing is just saying waiting for all nodes so it's not so exciting but just know that you are getting there and we are getting there it's just there are a few steps left to handle that and uh that's exactly what we're gonna do in the next chapter so get some tea and coffee if you want to and i'll see you there hello and welcome to chapter 32 of the slotzer course in the previous chapters we've been talking quite a lot about our node service and creating stream controller in order to populate the stream control with the nodes and we also have a buffer locally called underscore nodes in our node service and so we're kind of like working with our notes in a really good and organic way and we also work with the new node view dark file where we created a stateful widget that had a text editing controller and i also allowed the user to enter some text we manage even to save that text as a new note into the database so we've done quite a lot however what wasn't so much fun was that it was a little bit of an anti-climax in that we we are able to create notes but we're not able to actually display them so we're populating the database with new notes but no one is able to show them on the screen and that's what we're going to take care of in this chapter so let me bring the code that we've written so far to the screen here and um i'm going to clear this get status just to make sure everything's working fine yeah the visual studio code i'm going to bring scrcpy to the right hand side and we have to now talk about a little problem that we have with our nodes service you see if you look at the code here i'm going to increase the size so you see better so if you have a look at our note service and we have this uh shared instance that we've created here okay so whenever somebody says note service parenthesis then they're actually not creating any instance they're not creating a new instance of node service but they're going through this factory initializer which in turn calls this shared static final which in turn calls this internal or private constructor that means we've created a singleton so creating a new node service over and over again is not gonna um create a new instance he's just gonna get the same shared instance and then whoever then starts talk reading or you see all notes in here properly all notes is delegating its responsibility to the node stream controller or stream however our node stream controller is a broadcast stream controller and what that means is that a stream controller that doesn't really hold on to its current value for new listeners so let's say you have a stream controller that is sitting here and you start listening to events uh to that stream controller from one place and then an event comes into the stream controller and stream controller says oh um i have one listener right here i'm gonna delegate this information to that's uh that listener all looks fine however however after the propagation of this event into the stream controller the stream controller is not going to hold on to this value when a new listener comes in from another side so any new listener to your broadcast stream controller is not going to be informed of the current information which is populated in that stream controller so if you're familiar with for instance uh reactive programming with rx you may know this as a published subject and the same is true if you're for instance versus using rx java or rx scotland rx swift even if you're doing like um combined programming with a swift ui you will know these as like published subjects so a stream controller that is broadcast is not gonna hold on in to its current uh value for new listeners we need to we need to remedy that and the way to do that is just to move the initialization of node stream controller to our initializer right here as we'll soon see so i'm going to do a little bit of a shuffling of screen sizes in here all right so as the caption indicates what we need to do and we need to make this notes stream controller which is let's see where it is it's right here we need to make it a late final so grab the data type from where it is and just say late final put the data type in here and then remove the equal all right so now it is our responsibility to ensure that this node stream controller is actually initialized upon constructor upon constructing a new instance of our node service okay so let's go ahead and do that inside shared instance which is right here so what we need to do now is to say node stream controller is a stream controller list of database nodes and then we do the exact same thing as we did before using broadcast however what we're going to do in here is to use a property inside the broadcast stream listener called on listen so this unless and uh callback is going to get called whenever a new listener subscribes to our note stream controller note stream controllers stream so upon this happening we need to ensure that our node stream controllers stream is populated with all the values that we've currently read from the database so let's go ahead and do that so we're just going to go ahead and say notes stream controller sync add notes just like that all right so this ensures anyone who starts listening to our to this property all notes which in turn uses the no stream controller if it's a new subscriber then it's gonna the unlisted um callback is gonna get called and then we're gonna populate our stream controllers a stream with those notes that we've already read from the database okay let's now move to the next note before we can actually get on with the rest of this chapter as the caption indicates as we shouldn't close the db upon hot reload after opening db we shouldn't close it otherwise upon every reload it gets closed so the problem that i'm referring to is in inside our notes view and it is right here inside our dispose so upon doing hot reload what we're doing is that we're saying node service close which in turn is going to actually close the database but remember node service is and is was and is supposed to be a singleton where upon creation and upon doing an open one time it should keep its state so we shouldn't play with closing of the database inside any of our widgets because that is going to interfere with the internals and how the node service is actually supposed to work so what we're going to do as you can see since this pose function in here the overwriting overwriting of the dispose function the only thing it was actually doing was to close the node services database we're just going to remove this function for now because we have nothing else to dispose of at the moment in our notes view all right um so what we need to do is actually get to the meat of this section which i'm so excited about for this chapter and that is to start working with the list view and what we need to do is to make sure that we have a list that we can we can grab the data that comes from our stream here stream builder you can see it reads all the notes and right now we're just saying waiting for all nodes so we're going to change that and instead we're actually going to start using something called a list view now list view in flutter is an amazing widget which i can actually show you here so if you just type list view and then command and click control click on linux and windows you can see it's a box scroll view extends box scroll view which in turn is a scroll view which in turn is a stateless widget so a list view has uh some function some really great functionality uh that it exposes using is builder we can see here it has a builder function and i believe it's a static function here or it's actually constructor great okay so it has a builder and inside your builder you will be able to pass two important parameters to this list view so we're gonna say we return a list view instead of that little text that we had which right now says waiting for all notes in here we're gonna say we have two parameters first we are gonna tell it how many items it has to render on the screen so we're going to say item count all right and for the item count we need to actually listen for this snapshots data so remember the stream builder at the moment is listening for all notes and so that means the data that comes from snapshot is actually going to be your um is going to be the all the notes that we've read from the database so what we need to do now is just to ensure that upon waiting um in here so i'm gonna actually remove this and i'm gonna say if snapshot has data so that's a property on your snapshot that exposes whether the snapshot has actually pro can actually provide you with some data and i'm going to put an else in here and upon else we're also going to say return con circular progress indicator okay and if the snapshot has any data then let's grab that data so i'm just going to say final all notes is snapshot that's data as a list of database notes all right and what we could do we could just say return const text got all the notes something like that and we could actually print these notes to the screen if you want to it's we could say print notes and i'm going to bring the debug console up then i'm going to clear the logs and change the screen layout so you see it better and i'm just gonna do command s alright and i can see at the moment it's just saying your notes so meaning that we don't actually have any notes so if i go in here then you can see all of a sudden we got a new note populated into the database just because i went here and i said i'm printing some notes so so i'm gonna say hello okay see as i'm changing this our snapshot is actually getting updated with new information and it's constantly printing and it's the note id is the same and you can see his text is actually changing and if i go out then you can see well it's just at the moment says got all the notes meaning that you have some notes so if you're seeing a circular progress indicator instead of like a text at the moment that we're saying all the notes it's probably because you were like me and you didn't have any notes in the database all right okay now we have all the notes so how do we then render these so what we need to do in here we're going to say return list view i'm going to change the screen layout let's say list view builder and you remember i mentioned before we need to populate this listview with two important parameters one is the item count and at the moment the item count is all notes count links and then we have our item builder get some help from your editor to complete this you get a a build context as the first parameter of type context and then you get an index okay now inside your item builder your job is if you look at the at the signature of item builder it says it's a function that takes two parameters it build context and an integer for the index and it has to return a widget you see here so you could return anything in here you could just say return text item something like that okay it's not gonna look so pretty though and actually i can see maybe did we lose our item maybe in here it is possible that there is something wrong with our note 2 that it's like deleting the notes it could be so i'm just gonna do a hot reload here and my scr cpy may actually die no but uh it's it worked without a problem so we have an item so if that's if that's what you're also seeing maybe you could do a hot reload because we've changed our nodes service so it could be the problem that our uh we just needed to do a hot reload for this unlisten to actually get called all right so that's what we're seeing at the moment so i can see item in here and i'm gonna press the plus button so and i'm gonna say hello world in here and i'm gonna go out and all of a sudden you see two items appearing in here okay but this is not so pretty because displaying text on the screen is not so nice and you won't have uh you won't be able to easily add interactions to these items because what we want ideally is for these items to appear on the list and then they have like their own sizing so they have a good height so that they are separated a little bit from each other and as you'll see in the next chapter we're going to work with um deleting these items so we want the ability for the user to see some sort of an icon next to each item using which he or she can click on that icon and delete the item so text in itself is not going to be able to provide us with all that functionality that we need so what we need is a little bit more sophisticated widget and it is called list tile so let's do that let's just say we return at least tile okay and our list tile is gonna have a um a title so that's the only thing at the moment we're gonna provide it with and you can see it's a widget and for the widget of this list and for the title of this list style we're going to use text um right there okay and i'm going to put some commas in there so for the text what we're going to say then is the text in itself is we want to grab the text that is entered in that note so you see we have all the notes but we don't have the current note so the current note that we're actually reading its index is going to be provided to us using this item builders index so let's go and say final um notes is all nodes at that index so that's the current node that we're returning a list tile for okay its text is gonna be the note text as you can see here uh i can see i've written tile here but it should be title and in here we have to have a semicolon all right so if i do command s in here you can see now we have very i mean a lot nicer and prettier versions of those texts and you can see that they're right here it says hello and hello world and those are the texts that we entered you can actually test that and say my new my new notes is entered here and by pressing the back button you'll see that your note is appearing on the screen all right but what we want to do here is if you enter a lot of text in your in your notes so if i go and say here is a very long text that i've entered and i don't want it all to be displayed in one tile and then nodes view so we have now a node that is quite large but this is in it in itself is going to break a little bit our layout you see in our notes list we don't want to render the entire note we somehow want to cap the amount of information that we're displaying to a size that is reasonable and since our notes don't have titles we could infer the content of the note by simply rendering just one line of text and the user should be able to then say oh that's what i've written kind of in my notes and as you'll see in the latest later chapters we are going to allow the user to also click on or tap on these existing notes in order to go and see more information about them so it's not the end of the world if you don't display like the entire note to the user and as you'll see when users start to enter more and more information in their notes it's actually not desired uh desirable to render the entire note because imagine a note is two pages long or you're gonna have like two very small notes and then two pages of long of one note it's it's not feasible so actually it is feasible but it's not a good user interface so i'm going to put a comma here and i'm just going to use a property in our text called max lines and i'm just going to say one and so as you'll see here then what we're going to do is to make sure that the user kind of understands that there is more information in here than what we are rendering so we want to put like ellipses at the end of the text that don't have enough space to render themselves fully so we're going to say soft wrap and as you can see the information is whether the text should break at soft line breaks so make sure that it's true and then we're going to say overflow and we're going to say text overflow ellipses like that and now you can see it says here's a very long text blah blah blah and then dot dot so this is a good indication then to all users to know that well there's more information to be rendered but there's not enough space for that information to be rendered on the screen right now all right so i think i mean we've looked at how that all works we've actually demoed it so we don't have to do a separate demo for this we've been looking at it as we've been developing and the application and that's one of the beauties of flutter so we don't have to do anything about this demo right now and you will probably be surprised that this is all we have to do right now for the notes view there's not much more to work on we've written we were able to at the moment create new notes and we're able to display those notes and one at a time inside this list view builder so you'll learn how to use the list view builder as well and what we can do as is a tradition we're gonna go and commit and tag our work so i'm gonna do some reshuffling on the screen so you see what i'm doing a little bit better and i'm gonna go to my built-in terminal here and we're gonna have a look at the status can see there are two files changed so let's do git add all and let's commit this as step 15 and before committing it you can see your git lock from before the last commit was step 14 so and you can also look at all the tags and we have up to tag 14. so let's go ahead and say git commit and we do step 15. now i'm going to push that commit to github or if you're using bitbucket or any other provider that's fine too and i'm going to tag this as step 15 right and then we're going to push our tags great that part is now done so we've done what we promised to do in this chapter the next thing that we have to talk about as a tradition in all the other chapters is at the end of every chapter we'll talk about what we're going to talk about in the next chapter and you can see that we are able to create notes uh we're not able yet to update notes we're going to get there soon but we also need to allow the user to delete notes so that's exactly actually what we're gonna take care of in the next chapter and the next chapter is not gonna be a huge chapter either just like this one so it's gonna go very smooth but we're gonna do some quite heavy refactoring on our project as you'll soon see so grab some refreshments if you want and i'll see you in the next chapter hello everyone and welcome to chapter 33 of this flutter course in the previous chapters we've been talking about how to create new notes and how also to display those notes on the screen um and now it would make sense for any user of our application to be able to delete the notes that they've created already and we are not right now giving that functionality to the user and that's exactly what we're gonna work on in this chapter and just a heads up we're gonna work quite a bit with refactoring so things are gonna get a little bit uncomfortable where the code isn't gonna compile but we're gonna fix that soon and right after breaking it so we're going to work a little bit about on our dialogues as well you see we have a few dialogues at the moment that appear on the screen and for instance will we display an error to the screen or to the user where we for instance say oh you couldn't log in or oh your password was incorrect or we couldn't register this user because it's a a weak password entered so that's like our error dialogues and we also have a dialogue that we display to the user when he or she's trying to log out of the application so we have two dialogues at the moment and in this chapter what we're going to do is we're going to consolidate how we also display our dialogues to the user as part of delete functionality because you see the delete part as well the way we're going to do it is we're going to let me actually bring the scrcpy to the screen so how we're going to do it is that we're going to put a little delete icon next to every item on the list and we're going to allow the user to tap on those icons in order to display a dialogue now this is going to be the third dialogue and um a colleague of mine that i work with which i really admire his way of working he mentions that he makes things reusable when he gets to the third time of doing the same thing again so now we've written two dialogues to this point and we also now need a third dialogue and that's the point that maybe we should actually consolidate all our dialogue displaying to one function and then from other functions we're just gonna reuse that okay so that's what we're gonna do in this chapter so let's have a look at the code a little bit i'm gonna um i'm gonna bring the screen to a little bit um larger display so here so these this is our application the way we've listed left it at the moment so like that visual studio code and we have a cr cpy there as well okay so let's then have a look at our as a caption in case we're going to have a look at our error dialog so let's go ahead in our let's see what we have constant services crowd utilities we have and we have a function here called show error dialog which in turn says show dialog and then it says alert dialogue okay then if you have a look at how this is constructed the only thing it's doing is saying like hey i have um hey i have a title then i have just one action with a button and also and that action doesn't return any value and also we i have some text to display all right great now let's go to our notes view if you look at our notes view at the end of notes view we have this logout dialog what does this do it's the same thing it has show dialog it has an alert dialog inside it it has a title and some text but it has two actions and these actions they do different things so one action does uh if it sends a value of false the other one sends the value of true so every dialogue that appears to the screen so let's say this one for instance our logout dialog that's the one we're looking at right now the cancel button sends a false value and the log out button sends a true value so the dialogs are all very similar they have a title they have some contents and they have some actions that the user can take on those dialogues and these actions then have their own values and that's what we're going to do in our application right now is that we're going to consolidate all these into one generic function that is going to kind of allow us to customize it to our needs all right so let's have a look at how we can achieve this so as the caption indicates here we're first going to cut things from the source and that's like the strategy that i use a lot in software development so if i'm gonna disrupt things and i'm gonna like change the way things work i'm not gonna be scared and i'm really not scared of making things break and i in my opinion you may think differently but in my opinion it's really good to cut things from the source break the code and then start fixing things one at a time instead of trying to make sure nothing breaks while you're refactoring the code so that's what we're going to do here as the caption indicates we're going to go to short air dialog let's see if you can find it i like to use command p in visual studio code i'm going to say the show error dialog in here and what we're going to do is just we're going to remove all this code that is there okay so that's that part and what we're also going to do is um as the cache indicates remove the show log out the dialog from notes view since we're going to have a generic one so go into your notes view in here and remove this show log out dialog all right we're gonna get errors that's okay and you know this code that we removed also here show error dialog is used quite a lot so by removing it if i like search for show air dollar you can see we're actually using in seven places so all of those places are now gonna have an error that's okay fine we're gonna fix that soon so don't worry about that all right so what we need to do in here is before we fix all of that we're gonna start basically creating our notes list view all right so at the moment if you look at our notes view what we have is this beauty in here which is doing quite a lot of work as you can see it's it has a future builder inside the body of the notes view and it has a stream builder and a lot of code in here it would be really great if you could separate this code into its own place and we could call this widget like a notes list view and that's exactly what we're going to do in this chapter so let's go ahead in our views inside notes in here in your views inside notes let's create a new file and we're going to call it notes list view dot parts okay like that and in in notes list view what we're going to do is going to say the notes list view is a stateless widget so we create a stl which is a stateless widget and we're going to call it notes list view as we've seen it before we need to import material so i'm going to do that right now so all those errors are going to go away now what we need to do is we need to actually pass a a list of notes to this notes list view so that it can render them because you see all the logic for retrieving the notes can stay still in the notes view but all notes list view is interested in is a list of notes to display so let's go and expose that as a parameter in our notes list view so we're going to say final list of database nodes and you can see database node is not imported right now but visual studio code is going to be smart enough to import that so if you're actually yeah if your editor like if you're using vim or something on linux or even mac and windows if you're using that you may have to import these things manually so um but the import statements i believe i mean if you've gotten to this point in the course you should be uh like savvy enough and you should know all these things enough in order to be able to solve that yourself so um so i'm not going to repeat all that information again just make sure that your database note is in context in at this point so that's going to be our notes and also this notes view as i mentioned in the previous chapter but maybe it's actually worth mentioning in this chapter because it's very relevant what we're going to do is beside every note to the right hand side as the trailing tile widget we're going to display a little like a trashcan icon that the user can tap on in order to delete a um notes and what we're going to do then is to make sure that that we can basically call a little function to show a delete dialog to the user so upon you pressing the delete button we're going to display a dialogue and the delete dialog is going to be very similar to log out like saying now hey hey you're deleting this note are you sure and that dialog is going to have two buttons yes or no or something like that and upon pressing no we're just going to dismiss the dialogue upon pressing yes then we're going to delete that note from the database all right so what we need is you can see the notes list view at the moment isn't like it shouldn't have any connection with the notes service it should be the notes view that has that connection so this is how you should also like do your components in flutter in that you shouldn't leak your services everywhere so if the notes list view could somehow delegate the deletion task to the notes view that would be ideal so the notes list view could display the dialogue it could just say hey are you sure and if the user then says yes the notes list view could then delegate this information back to its parent and say hey do something with this information okay so let's then go and create a little callback definition using typedef excuse me and we're going to call it delete note callback okay and this is a void function that takes a database note oops a database nodes i'll note like that so we're saying we're defining a function that we're then going to use in our nodes list view which we call we which we use as a callback that will be called when the user presses the yes on this hypothetical dialogue that we're assuming gonna display that user okay so let's go in here and define that let's just say um delete node callback and we're just going to say on delete nodes so this is our callback and you're now getting some errors from a flutter saying that these parameters aren't defined so i'm going to use visual studio code and to say define these parameters for me i'm also going to make them require parameters like this so that's great we have still some errors in our application so but we're going to continue building until we can fix all these errors okay all right that's fantastic so that's the first part that we have to work on so let's then go ahead and um take our notes view the way it is right here and you see we already have a list view builder i'm just gonna go and grab this list view the way it is from there and i'm i'm actually gonna cut that and bring it into nodes list view inside the build function alright so inside instead of returning a container i'm just gonna return that code that i've just pasted that i just cut all right it looks absolutely horrible at the moment it's because i mean we have so many errors but i actually like that kind of stuff to be honest with you some developers get nervous when they have lots of errors in their code and they just want to patch them up as soon as they can but we're gonna work just one step at a time as we say in sweden we say it means one step at a time we're going to fix these errors and at the end of this chapter everything's going to work i promise you so let's go in here you can see the first error that we have is all notes and what all notes is giving us an error for is that it doesn't exist in this context and that's because we have something called notes all right so let's go in here and say now we're using notes and in here we don't have all notes either so we're just going to say notes notes and that note is going to be extracted from notes at that index and the exciting part now is that we don't just use the title property of our list tile anymore we're going to start using something called trailing and trailing is a as a property of list tile that as its name indicates it's going to allow you to specify a widget that needs to be displayed at the end or the trail of every list tile and this is where we're going to use an icon button so to display our little trash can okay so let's say icon button and in this icon button what we're going to do then is we're going to define the uncrest which looks like this and it's icon then it's going to be icon of icons delete i believe it's called let's have a look at how delete looks like and you can see it's a little trash can fantastic and make this cons to make the analyzer happy as well all right so what do we do i'm pressed so what we need to do on press is as i mentioned before we need to take care of the displaying of a dialogue that says let's just call the show delete dialogue okay so this show delete dialogue we're going to call it and we expect it to return a true or false remember we haven't implemented the show delete dialog that's okay we can put some constraints on the interface of this function yet but it doesn't yet exist so let's just say that this function show delete dialog takes a build context and it returns true or false to us so if the user says yes i want to delete some item then it it returns true if it's if the user says no then this dialog should return false to us okay so let's go ahead and say final should uh you should delete is a weight and when you're using a weight you need to make your own press function async then we're going to say await show delete dialog we don't have that function remember but that's okay and when we say should delete okay if this is boolean then we say if should delete then what we're going to do is we say and we call our on deletes notes with the current note okay so that is just the implementation of this widget notes list view all right but don't worry about these errors we're gonna soon fix them so and just save this file as well now we need to move to the next item and that's our own generic dialogue you can see we're going to create a generic dialogue dart which is so important because pretty much this show generic dialogue and the variations that we're going to create on it is going to fix all these errors that we have in our application right now so i'm actually happy to start working on it i don't know about you so as the caption indicates we're going to create a file in lib utilities dialogues generic dialogue dart so we have what folders do we have in here we have lib consonants enums services utilities all right but inside utilities we don't have at the moment a dialogues folder and remember that we removed all the contents of this show error dialog let's just delete the file now we don't need that so i'm just gonna delete it and move it to trash so now inside utilities we have nothing so let's go create this new file as the caption indicates we're gonna say it's gonna be inside a folder called dialogs and we're going to call it generic dialog.art all right i'm going to get rid of the sidebar and we now need to start implementing our generic dialogue this show generic dialogue is going to be a little bit complicated and um and i'm saying it a little bit complicated simply because it's going to use generics and the reason um i've basically decided to make it generic is as the name generic indicates this generic dialogue i mean the file also says generic dialect so you need to kind of know already what you're getting yourself into the reason it has to be generic is that it needs to be able to produce different sorts of values let's go to our notes list view and you see here we're going to say show delete dialog a function we haven't implemented yet and show delete dialogue all of a sudden it's going to return true or false okay that's one thing how about in the case of login view so let's go to login view how about this case show air dot log remember show error dialog is a is also a function we're soon gonna develop which we have before we we killed it we have to develop a new function called show air dialog which in turn is gonna use our generic dialog but in this case it's not gonna return true or false so we need to make sure our generic dialogue as its name indicates is a generic function that can based on what you provide to it is able to return those values to you and what i mean by what you provide to it every item every option or every button that is displayed in our generic dialog is gonna have a value we're gonna assume that all the buttons that you display in any given dialog is going to have values of the exact same type so a dialogue that shows a yes or no button is going to have two buttons each of which contains a boolean value one true the other one false or maybe you want to display 10 buttons and two of them have the value of true and the other one had the others 8 have the value of false but what i mean is that the buttons inside your generic dialogue are going to have the same data type all right so we're going to call that data type t all right so let's go ahead and define this um show generic dialogue so we're going to say that this dialogue actually returns um a future of t and um what we're going to say we're going to say show generic dialogue and it's it's a function signature it kind of looks like this all right so what does it actually mean t optional and that's because remember on android for instance when you display a dialog to the user the user can actually press the hardware down button in order to dismiss a dialog without actually responding to it and ios is actually not so much like that in is when you display a dialogue it's a modal that the user has to reply to unless you create your own dialogue or if you're doing maybe something hacky on the side to say that oh if the user taps outside the dialogue then it should disappear otherwise dialogues in ios are modal and have to be responded to however in android it's possible that a user dismisses a dialogue without actually responding to it and in this case the show generic dialogue should actually return nil or null depending what language you're talking about if you're a python developer you'd say none so so we're going to define this saying we have a generic dialog that returns some sort of a optional value all right and the first parameter that we need is a build context so let's just say build context and we need a title and content so we're going to say required also before we do that let's also have a look at this thing that says build context isn't defined and that's because we have an important material so let's take care of that and we have to have curly brackets in these places because required actually requires that okay so the next parameter that we have to implement is the title and then the content so both are going to be text or string so that's the title and now i'm going to copy paste that i'm going to say content in here content all right now it's exciting part now what we need is some sort of ability and some sort of way for the user to be able to specify like a list of um a list of buttons to display the to the to the user now every button if we say every button by default should have for instance we should we're representing every button as a text button that every text button needs a string to display all right and then it will have an unpressed so what we're telling what we're saying is that okay we should be able to render multiple buttons and every button should have a text and also we set from before every button should also have some sort of a value all right which is t optional so we need a way for the user to specify a list of buttons each of which has a title of type string and also every one of those buttons should optionally have a value so that's best described with a map of string as titles and a value of t like this all right so we're going to type def that we're going to say we have a definition of a and we have basically a type to finish and we're going to call the dialog option builder and we're going to say it has it's a generic okay and we're going to say that is equal to a function that returns that value so let's also see the map all right key expected to find all right and that's probably because i've misspelled that am all right so now we have an option builder so we're gonna then use that option builder in our function so you're you'll see soon how we're going to use it so i'm going to say that we have a dialog option builder and let's just call it options builder okay so we have all those bits and pieces in place now what we need to do is inside this function actually use the build context to display a dialogue to the user so before we do that let's grab all the options that the caller wants us to display so we're going to call it options is options builder we call that function and now you'll see options is it smart enough to understand that yeah it's a map of string dynamic okay it doesn't understand yet what it is so let's go ahead and say in here in this function we return a show dialog of t all right and in here we have two parameters that we have to pass one is the context the other one is the actual builder function all right some help from your favorite editor to complete the builder function which is very simple it just takes to build context all right and in your builder we are going to return an alert dialogue this you should already know from before we've worked with alert dialogues and show dialogue from before so this is nothing revolutionary so for the title we're going to say we have a text which is equal to which contains the title string for the content we're going to say also a text which includes the content all right and then we're gonna go into our actions and this is this is the exciting part for me because for the actions what we need to do you see our actions are defined in here every key inside this options is the title which is defined by string of the actions of our dialogue so we need to start mapping them so we're going to say options keys keys and then we map them all right and this let's just call this a option title and we're not going to use a shorthand signature in here and we're just going to do it like this all right so now in here in the option title we're actually actually gonna return a text button so let's let's get the value first of this key so i'm just gonna say um final t value is equal to options at the option title like that right and now it's saying that yeah you're not using it that's fine we're gonna we're gonna fix that soon and this huge error that we're seeing here is because you see actions it requires an iterable i believe no it's actually a list of widget but when you do a map on your keys it's going to return an iterable so to fix that we're just going to go at the end here and say this is to list all right all right so let's now fix the rest of the problems i understand i mean this is quite a lot of errors and you may be a little bit overwhelmed by this but that's okay we're gonna fix them one at a time so a semi column at the end so to get rid of that huge er at the end and then what we're going to do in here where we get the value we're going to create a text button so let's just say return a text button every option and what the text button needs as we've seen before is two parameters unpressed and it also needs the i believe it's tiled and we're going to say the child is equal to text of our option title right so i mean you may be a little bit confused by all of this that's okay what we're doing is very simple we have like a list of titles to display for every button so every button has one title and that title is inside this map of string and the reason it's inside a map of string and an optional t is simply because we don't want to have we don't want to manage two separate lists a list of titles and a list of values and then we're going to match the titles with the values and map is already doing that for us furthermore what a map of string with a t does is ensures that every string or every key in this case of type string is unique so you can't have two buttons with the same title and different values so the map is perfect for this case all right and what we're doing in here for the actions of our alert dialog we're saying that okay every key inside our map is an option title is a title of a button all right so we're mapping that what are we mapping it to every one of those titles of type string is going to be mapped to a text button whose child is a text of the actual title which is inside this key all right i understand it could be confusing but please just pause the video have a look at the code and i'm sure you'll understand it better after we actually thought about it yourself the values then are going to be extracted of this type and what we're going to do is we're going to say let's see final value and in here if you look at value it's going to be dynamic and what we need to do is just to make sure that say if value is not null and we're going to say navigator of our context it was written already then i'm going to say pop it with that value otherwise we're just going to pop off just pop all right so this that is now you see why we're defining the value as in as an optional because you see some values some buttons on our dialogs may not actually have any values just like we have in our login view if we go back in here this login view is going to have an error dialog and this error dialog is going to use our generic dialog but this air dialog is just going to have an ok button it has no value the okay is just an ok just dismiss the dialog and that's exactly what this is going to do so as you'll soon see the way we'll implement our new show error dialog is going to use our generic dialog however it's going to place a little um option in there that says ok and that ok has a null value all right perfect a lot of talking a lot of logic but that's fine we sometimes need to do this okay wow um we've now written our generic dialogue what we need to do is we need to start using it and that is inside our error dialogue that we're going to implement now so let's go ahead and create an error dialog so i'm going to bring up my notes and let's as the caption indicates inside dialogs let's see where it is inside dialogues we're going to create a new file called error dialog here now inside error dialog what we need to do is we need to use our generic dialog so we need to have an import in here which we're going to get visual studio code to help us with so remember error dialog is going to just show an ok button it has no value so it the short error dialog is going to have the signature exactly as it had before which is a future void so let's go ahead and do that and we're going to call it show error dialogue and the only thing i mean the two things that the shower dialog needs is a build context and a text so we're saying build context and we're also going to say a string of text okay and let's import material to get rid of that error so that's that and then in here we're actually going to return an instance of our show err show generic dialogue and i believe it now should be imported is it not imported automatically in here it's not yet but somehow it's finding it and i can see we have a show generic dialogue actually inside in here so this is not the one that we're actually gonna use so we're gonna use the one with uh like this and then we're gonna say our air dialogue avoid so let's import our own uh show gener um show generic dialogue so was it a show general dialogue i'm actually curious general dialogue that's interesting so there's a function called show general dialogue but that's not what we've created we've called show generic dialects so be careful a little bit with that because i actually tripped on that right now so let's go back to our error dialog and say show generic dialog and it's going to also import that form you know so that's that's the correct one okay so put a comma at the end to get formatting also working fine and now add a comma in here to get the formatting finding there as well now the title we're going to hard code that we're going to say an error occurred like this and the content is just going to be the text and our options builder now is going to be i remember an options builder if you go back in here to our generic dialog is a function all right that returns that so let's go and define an inline function in here and we say that oops to remove this and we say it's a function that returns a map and the key in here is just going to be okay with the value of null all right see how see how generic that is now so we're actually defining saying that this is a show air dial again it just doesn't return anything it's just a void all right and to make it cleaner you could actually specify here that this is a void all right that's that part so now we've worked on our error dialogue um and now what we need to do in order to make our code a little bit less scary with so many errors at the moment that we have let's go and clean up some of these errors and let's go ahead and use this show error dialogue everywhere okay so let's go to our views and have a look at the login view you can see now we have show air dialog and and now we have our own implementation of uh show air dialog so let's get help from visual studio code to import our error dialog and all of a sudden you see all the errors in the login view and disappeared you can see we're in loginview. so let's save our login view and we have an error in here from our previous import which was show air dialog dart so let's remove that as well so your login view should now look quite clean i'm going to close that and let's then i'm going to save all of these things that we have in here because we have so many windows so many tabs open that it's kind of scary so let's then go inside the register view and clean up this import so let's remove the old import from utilities show error dialog and let's go and to these errors that we're getting here for show air dialing and get visual studio code or your favorite editor or id to auto import our new function called short error dialogue which resides inside this utilities dialogues error dialog okay now you remember now that we also broke our notes view here which at the moment uh let's see yeah we've broken notes view simply because we're not returning anything in here because we migrated or moved all the code to the notes list view so what we need to do now is to go and basically work on our show delete dialogue okay so that's not the one that we we need we need to work on the notes views log out functionality which is here show log out dialogue you see so we need to create a new logout dialog as well and this this log out dialog is going to be very similar to how we created our um error dialog so it's gonna be very similar okay so let's i'm actually gonna i don't know if it's worth copying this code i usually don't like copying even if it's my own code sometimes i do but in this case i think it's actually better that we write it by hand okay so let's go ahead as the caption indicates inside dialogues folder create a new file called log out dialog so in here i'm going to say new file log out dialogue drop down and in the log out dialog so i'm going to go to my notes as well and log out that one all right so let's go and say and then we need a function called show logout dialog all right as we have it here okay so i'm going to just copy that name so we're going to say it's a future of boolean and call show logout dialog and the only thing it needs is a build context okay we're going to get an error for build content simply because we don't have it inside our file in here and you see now the only error that we're getting is saying that the body might complete normally which means yeah it's not returning any value at the moment and we're going to fix us so what we need in here we're actually going to return our show generic dialog and auto import it a comma at the end and a semicolon just to get the formatting right the context is there and we're in this case we're actually going to say that show generic dialogue is going to return a boolean value all right so the context is there the title we need to specify kind of we're just going to say log out and for the content we're going to say are you sure you want to log out the optional remember it's a function we're going to make an anonymous function in here and returns a map and for the option of cancel we're going to say false and for the option of logout we're going to say true all right we're getting a huge error in here saying that there is a future of boolean you're returning a boolean optional for a function that is supposed to return a future of bull again remember on some platforms you're able to dismiss your dialogues without actually responding to any of the options presented in the dialogue in those platforms you actually need to guard yourself against that case by returning a default value so let's go in here and say then so if we get this value which as you can see is an optional bool then we say either return that or just return false and that's it we can put a comma at the end as well just to get the formatting right okay perfect um now what we need to do is now that we've written our show logout dialog we have to put it to use so let's go into our notes view and get help from your favorite editor to import your new logout dialog in here so that error goes away okay so we've actually worked on that so what i want to do is uh edit my caption a little bit and i'm sorry about and i'm sorry about this because this caption wasn't completely right so i need to fix that that's fine now let's now now that we've worked on the notes list view let's go and bring notes list view inside notes view all right so you can see here we have our notes view and but we also have our notes list view which we have to import in here i'm going to go to my notes and just to make sure i have everything in place all right so in this case that we have all notes let's go ahead and say we return an instance of our notes list view and this is gonna auto import it for me so like that and for the notes i'm going to say here are all the notes and upon the user wanting to delete a note i'm just going to get visual studio code to complete that for me you can see here and we get the note that the user wants to delete all right then in here we're going to make this function asynchronous and just a wait on our node service delete this node with this id all right i'm going to save now if you look at your code in here you can see we have one error here in our notes list view and let's go ahead and fix that and we can say it says show delete dialog and we haven't yet actually written the delete dialogue so what we need to do is need to go and fix that actually so it creates a delete dialogue as well so let's go inside our dialogues that we have here in here utilities dialogs so let's go and right click on it and create a new file called delete dialog and delete dialog is going to be very very similar to the log out dialog so let's just go ahead kind of maybe we could use the log out dialog so copy the code from log out dialog and bring it into your new file called delete dialog and just paste it in there and we're going to call this function show delete dialog okay and it's going to create a generic dialogue in here and in here we're going to say delete and we're just going to say are you sure you want to delete this item the option builder is going to be cancel false and then we're going to have an option that just says yes true all right so now you see how easy it is now that we have a generic dialog just we're reusing it everywhere okay so then let's go back to our notes list view and fix this function fix the calling of this function and get help from visual studio code to import our delete dialogue and that error also goes away so now i save my project and all of a sudden you see we have delete icons appear to our every tile and we should now be ready to actually put this into test so i'm going to tap on the hello world item here and now you see it says are you sure you want to delete delete this item pressing cancel doesn't do anything but if i press on it and say yes then the hello world note is deleted and our notes view is getting notified of that information from its stream builder because remember notes service as we have it here let's go to our services here uh crud and node service upon deleting a node let's have a look at the leaks node function here you see what it does is that if it could delete a node it actually removes it from its array of nodes and it notifies the stream controller actually no that's the delete node oh yeah basically it removes the node and then puts the entire array of nodes in the node stream controller okay so that's how the notes view is getting notified of a deletion of an item we can delete another one if you want and that's it so well done great job for sticking with me throughout this chapter this was probably one of like the most challenging chapters in that we had a lot of errors from the beginning and we had to fix them but one of my goals for for this course is not for you just to learn how to write flutter application but actually get in the mindset of a software developer so and every software developer they have their own preferences i included and one of my preferences when i'm doing refactoring is like to cut things from the source as i mentioned in the beginning of this chapter so that's why we got so many errors in the beginning but you stuck with me and we fixed all those errors and now we came out of this chapter actually quite victorious so now we have the delete functionality what we need to do now is just to go and we because we've done a lot of work what we need to make sure now is to commit and tag our work so that we don't lose this work so um i'm gonna do some um reorganization on the windows here so you see things a little bit better i'm going to increase the size okay and let's see now if we look at the previous tags we've come to tag 15 from the previous chapter and now we need to do a tag 16 okay so let's go and look at the status we have quite a lot of things that we've modified we've deleted the show error dialogue from before we've also excuse me we've also added a whole new folder here on under lib utilities dialogues so let's do get at all and let's look at the status a lot of things changed okay and what we're going to do is we're going to commit these and let's just say step 16 okay and push your changes into your host git repo we're also going to tag as step 16 so and we're gonna push our tags if you look at your tags right now you have one two three four five six seven blah blah blah so we have all our tags up and including step 16. all right so that was for committing and also tagging our work as it's tradition we're going to talk about what we what we need to discuss in the next chapter you can see we have the ability to create new notes and we also have the ability to delete notes and also something that we didn't test is this thing that when we create a new note and if we back out of it you see that that note actually is deleted from the database so that's also working so we have the ability to delete notes and the ability to create notes but we don't have the ability to update notes and that's exactly what we're going to talk about in the next chapter so i'll see you there hello everyone and welcome to chapter 34 of the slaughter course in the previous chapters we've been talking quite a bit about how we can create and notes and how we can delete them so we've been working quite a bit with some generic dialogues that we've also developed in order to be able to handle error dialogues and also the log out dialogue for instance and also the delete dialogue so there's been quite a lot of work done on that side but we haven't really talked at all about how the user can tap on or click on their existing notes in order to be able to update that for instance and update that's a particular node so that's what we're gonna take care of in um this chapter so if we now start looking at the code that we've written you you will see that we've called the view that actually creates a note um the new node view however we're not going to go and create a whole new view that looks exactly the same as this new note view just so that we can update existing notes so the goal of this chapter is to reuse this view so that we can just use the exact same view but when we when the user taps on a note in the note list we're going to pass the tapped note to this existing view all right so that's what we're gonna take care of in this chapter let me do a little bit of a shuffling around here so you'll see the screen better i'm gonna bring up visual studio code as usual here i have scrcpy who is taking care of this android screen and we can then have a look at the first task that we have to do as you can see in the cache it says we have to rename the new node to your dart to create update node view alright so let's take care of that i'm going to close all the tabs in here and let's go and say command p visual studio code or maybe an android studio is another command that you have to execute in order in order to bring up the list of files i don't really know the command in android studio but if you're not comfortable with any of those you can just go to this new note view right here and we are going to rename it so let's just do that now so i'm just going to call as a cache in the case create updates note view okay create updates notes view like that if the updating i mean if if your editor is intelligent enough and it has some like um refactoring features built in then you don't have to do anything special for for this command to work but um you can see in here for instance now we've changed this file name to create updates nodes view but we haven't really changed for instance the class name so if i go here this thing is still called new node view all right so let's go in there and perhaps change that as well let me go to my notes uh let's see create update note view and we're going to go actually and rename this new note view as well so let's go ahead and do some refactoring in here so i'm just going to say refactor and let's see do we have any refactoring features here um we have rename symbol so maybe let's use that and i'm going to call it create update node view right let's see if it's successfully going to be able to rename this for me so i can see it renamed the class for me and it also renamed the state class which is exactly what i needed so if i now save this we should have some problems excuse me but i can see visual studio code was intelligent enough actually to rename the main dart reference to this route as well remember when we created this create or what we call it actually before it was called um new note view that note view was a new note view was actually being used inside our routes in the main function of our of our application inside main.dart now that we've renamed that to create update note view both the class name the stateful widget and its state then that new name should be used in main.dart so if you're using vim or any other code editor like if you're using sublime supply may not have this refactoring feature that can actually go and rename where you've used that symbol so you may need to do that by hand so you may actually get some errors in your main.dart file but if you get those errors don't worry about it at least you know what the problem is okay so you can go and fix it yourself all right so we've done that and now what we need to do is i'm actually going to press command s here and command s in here just to make sure everything's saved and as the caption indicates remember we also have our routes inside constants so you can see our route is still called new node route okay so i'm gonna rename this now and i suggest that you do the same thing too let's just say rename and let's rename that to as the caching indicates create or update node route okay so create or update snow throughout just like that and as you can see again visual studio code helped us quite a lot now it went and updated this as well you see right and something also happened in the notes view as well i can see and that's because you see the where we actually press the plus button in here to create a new node that was also using the uh previously uh named new node route but now it's updated to create or update node routes so all i'm trying to say in here you need to rename that route so that it becomes create or update new node route and depending on your editor it may be smart enough to have some refactoring features if it's like visual studio code then you're good to go just rename it but if it's not you may have to do that by hand so just go ahead and rename where you refactor in your code where you're using that route to use the new name okay all right so let's have a look at this dilemma now you see in our notes view when we create a new note we just say navigator of context push name all right now the goal here is when we create this nodes list view we're going to allow the users you see at the moment we have on delete node but we're also going to have a parameter called untap we're going to develop that soon but the dilemma here is that when you then say on tap we need to also go to this view into this route that we have create or update node route but we have to pass an argument to that route an argument just as it is for a parameter of a function or an argument to a function is like data that you pass to that route and you say hey i'm initializing this route but i'm passing some data to it so then that route can then in turn reactively sorry that ralph can then react to that and go and read that argument and say oh was i pass an argument yes then i'm going to do this was i not pass an argument then i'm going to do something else in this case if you pass a note to our create or update note route then it's going to say oh i have an existing node i'm just going to populate myself and my contents with that note and i'm not going to create a new node remember at the moment our create update note view we have this function set up in here that says create a new node we're gonna fix that soon okay but remember that at the moment when you go into that view by default it's creating a new node and we're gonna change that so that we're saying we're going to rename that and saying like create or get note or something like that soon you'll see um but in that function then we're going to say where we passed an argument where we pass an existing note if yes we don't have to create a new node if no we have to create one okay so the way arguments work then is if you have a look at our notes view where we're using push name there is a parameter in here called arguments and as you can see at the moment it is just an optional object meaning that well it can be no or no we're not we're not leveraging that at the moment but we are going to soon so at the call side where you're creating a where you're creating a route and pushing it to the to the navigation stack you can pass your argument using that arguments parameter okay and at the receiving side in this case are let's see create or update node view here in here you can read then your argument let's see let's go to some place that does make sense let's say in here okay you can read that argument calling now you don't have to type as i'm typing i'm just demonstrating something to you okay and we can use model uh route and we say of is context and then you can say settings dot arguments then that's where you basically get access to your arguments through your modal route so now you know how to pass arguments and you know also how to receive them all right so let's go to the next point um you see we may need to somewhere also in the future receive an argument inside our any of our widgets and that argument can be any type that you specify for instance you can pass an integer from one screen to the other or you can pass a string or you can pass an array or in our case you can pass a database node so as you could see in in this code let's go in here um what's this optional yes settings and then arguments you see at the moment this guy is an object so it doesn't really know what it is but it'd be really good if you could create a function somehow that allows us just to say for instance context get object of type t something like that so we could just say given a build context we want to extract an argument of any type from it if that argument exists okay and then we're going to use it in our code in here and to and we get our build context and then grab our notes out of it so it's what we're going to do is like create a generic way of extracting arguments from our build context and that's exactly what we're going to do now okay so to do that we're going to create an extension on build context and that extension is going to be called guest argument and as i've indicated in the um as i've indicated here in the caption at the bottom of the screen you can see that we are going to create a new file under lib utilities generics and a file call gets arguments so you can see we have utilities at the moment here and that utilities follow me just fold everything in here so it's not so scary to look at you can see utilities at the moment has a folder called dialogues under it but what we want to create is a folder called generics and then a file under that called get arguments okay so uh let's go ahead and do that right now so i'm gonna go to uh utilities where where to go utilities dialogues okay so i'm just gonna right right click on utilities and say new file and i'm gonna say generics lyrics and get arguments dot dart now in here what we need is um to just start writing our extensions so i'm just going to say extension and get argument on build context okay now if i typed build context visual studio code was smart enough to import material if you're using sublime or any other text editor it may not be intelligent enough to do that for you may not have like the extension to work with dart and flutter and kind of so you may have to import material yourself but remember we also only need um build context and modal route from entire material uh packaging here so it would be it would make a lot more sense if you just say show build context and modal route right so we're not going to use more from the material package than those two all right so let's go ahead and create this function so we're saying that we are going to optionally return a value of type t that means any type that you ask us to and we're going to call this function get argument okay and get argument itself takes t all right so in here what we're going to say is going to say modal route is model route of our build context or this because you see we we are creating an extension on build context and this identifier in here refers to the current build context on which the get argument function is actually invoked so if you're not familiar with extensions i've talked about them before and so it i think it was part of also the dart introduction in the beginning absolute beginning of this course so you may want to go back to that in order to understand how extensions actually work okay so remember model route in here if you look at it it can be an optional in here you see so what we need to do is to guard ourselves against that so we just say if modal route is not null and otherwise we're just going to return null we're saying that if we can't get the model route then we can't extract any argument from it okay so let's get the let's get all the arguments from our model route now so we're gonna say args is model route settings dot arguments okay and then remember args is also now an object as it was on the call site the call site may skip over passing an argument to us and we in that case we're not going to get any arguments which means args is going to be null in here okay so let's just guard ourselves against that so we say if args is not null and args is of this given type then we're going to return rx okay uh oops rx as t so what we're saying in here is that if we could grab any arguments from um our modal route settings arguments and if that argument is of the type that you are asking this function to extract then we're going to give it back to otherwise we're just going to fall through to line number 12 in here and just return and null all right now i'm going to save this file okay that was that part now what we need is let me bring up the caption so you see what we have to do so let's now go to our view which we call create actually it's easy now now that we have a lot of files in our project it's actually easier to navigate if we just do command p in visual studio code for instance to jump to specific files so in that file it is now called create update node view so let's go there and as the caption indicates our creates note in here let's have a look and see if we can find that function create new node here you see so what we need to do is we just need to rename that um create new notes to ask them captions to get create or get existing notes so i'm gonna do that i'm gonna say create or get existing note and again we just do the code smart enough to rename where i'm actually using that function as well you can see in here okay so you may otherwise if you're not using visual code or if you're not using the refactoring features of your favorite editor you may have to rename that a call site as well so i don't think i have to mention this again i think i've now mentioned it three times so just so you know if you're renaming something just make sure that all the call sites are also updated okay all right so now that we've done that we actually need to grab the existing nodes if it is already there okay so um so let's do that you can see it says in create or get existing no gets note argument if any all right so let's then in here say if we if our widgets like the widget that actually called us created us has passed us an argument of type database note then we're going to get that okay so let's just call it widget note is um we need now a build context because remember our extension was created on build context however this function at the moment has no build context so let's go ahead and pass a build context in here okay so let's then go into the call site and pass the build context in here call context which is passed to us in the build function all right so trusting that you've done that we're now going to go and say context get and you see now we need our get argument function in here but as i type nothing appears here and that's because we don't have an import so i can see if i just type get the argument and ask visual studio code to see if it can solve that problem for me it's saying that oh there is again arguments.dart file which has a function do you want me to import it so i'm just going to say yes please otherwise if you're not doing this you may have to import your get arguments.dart file by hand all right so now i'm just saying get arguments and remember get arguments function in itself has no parameters so how do you call this function okay how do you tell it to extract a t of like database node well that's very easy you just put this less than sign and and grade it inside like that and then you type the type of object that you want to extract so if we just say data base notes all right and now that we did that remember get arguments returns an optional object of that type and in this case our database node is then an optional database node all right meaning that you either have a node so that the user has tapped on an existing node and came here or you don't meaning that a user tapped on the plus button and came here okay so then we say if the widget node is not null meaning that we are updating an existing node so that the user has tapped on an existing node and ended up on the screen then what we're going to do we're going to save that inside our node private variable here i think we set it up somewhere around here you see so we're going to say our node is the widget node okay and in this case what we also need to do we need to make sure that the text field inside our on our screen and i can show you here so if you go here this text field it should be pre-populated with that existing notes text and the way we can do that i mean we don't have direct access to our text field but what we do have is this text controller which we set up in here text controller okay so let's go and set that text controller's text so i'm just gonna say text controller the text is equal to widget note dot text and then we're just going to return the widget note so the notes that we could extract okay otherwise uh what we're doing in here we're saying existing note notes so the logic is going to stay the same the rest so if we could extract the node from the passing widget or the color widget then we set that as our node set the text and then just return the widget note otherwise we continue exactly as we did before okay so let's see in here what we're also doing existing note we're just returning in but i can also see that upon doing a creates note in here we're not setting that note so what we need to do in here let's just say final new note okay and and then we store that note we say note is new note and then we just say return you know so in here we're also saving our notes okay so that's really good so we actually working with an existing notes all right okay so i'm actually not sure how this has worked before this may have been a bug in the previous um sections in that we didn't actually store the node in this node private variable so maybe we had that bug from before i can't be completely sure about that so i'm just gonna press back in here but if you had that bug as well if you were like returning just on a weight of node service create node and you weren't saving that i'm not sure how these um these functions were actually working because i personally oh i can see that we were setting it in here so we may not have to do that anymore so let's then go ahead and i mean this was quite smart but it wasn't that good idea that the widget's build function was changing like a core part of this widget so let's remove that now okay how it was working so that's the reason it was working but it shouldn't work like that all right okay let's move to the next section now um you see if we go back to this part in here if i press the delete button do you remember this we developed this in one of the previous chapters of this course we made sure that we have a callback and that callback was defined let's go in our notes list view i'm actually going to do it like this notes list view do you remember this callback it's called delete note callback it was just a function that returned nothing and accepted the notes and this way we could tell the notes view that hey the user wants to delete a note do it delete that now and that was being called upon the user pressing the yes button remember it's this view that is actually showing the delete dialog all right but if you look at that but if you look at this delete node callback what is it actually a call backup is a callback of a note all right so it has nothing really to do with delete it's just called delete node callback all right can we utilize this also to tell somehow when the any of these notes is tapped can we utilize the exact same function to tell the notes list view sorry to tell the notes view that hey you the user tapped on a note well of course we could do that because it has no return value and it just accepts a note so we have a little problem with the naming of this right now it's just called delete note call back but it shouldn't be all right so we're going to utilize that both for delete and also for tapping on an existing node so let me bring up the caption let's rename that delete node callback to just node callback so i'm going to right click on it i'm just going to say rename rename symbol and let's just call it node callback okay and now you can see it's actually renamed it here for me as well and everything should be working the way it was before so we don't have to do anything special it's just called node callback now all right okay let's move on to the next section now which is very related so what we need to do now is you see at the moment the nodes list view it's not handling at all the user tapping on any of these list tiles and we're going to fix that so i'm just going to go to my notes and make sure that i have all the information here so what we need now is just to make sure that the user can tap um on those uh on the on tap all right so sorry that the user can tap on these list tiles and then um we're then going to call a function just like the node callback and tell our owner widget that hey the user tapped on one of these just do whatever you want so let's go ahead and add a field here and say on tap sorry note callback and we'll just call it ontap the constructor is not happy now saying that yeah you have a final field that you haven't initialized so let's just add that here right after undelete and i'm just going to make this required parameter and a comma at the end just to make sure that you get the formatting right as well we're not using on tap right now and if you've noticed we've also broken the notes here that's okay we'll get there we'll fix that soon the reason we've broken note2 is because we're not passing on tap since it's a required parameter okay we're gonna fix this luckily in order to handle tabs on a list tile we don't have to work with gesture recognition or anything like that but what we could do is just to say untapped you see it's already there so there is a function that has no parameters and what we need to do in here just to call our own ontap in here and you can see we have to pass a database node and luckily we already have i believe a note right here okay so we're just gonna say untap and note that's it okay um so we're doing that now now what we need to do is to go back to our notes view and handle that case you see so i'm going to go back to our note 2 and and scroll to the part where we're getting an error and we have on delete um but we don't have the on tap so i'm going to go to my notes as well all right now in here right after on delete note let's go and add this untapped functionality in here and you can see visuals helping me and saying oh this function actually accepts a node so if i move my mouse over it it already tells me it's a database node and remember that's just what the nodes list view is giving us all right and then here let's make this function an asynchronous function the reason for that is because we're going to actually grab our um let me actually see if we have to make it asynchronous i don't think it needs to be async first let's just not make it asynchronous i had it as asynchronous in my notes and i thought that we have to do that but maybe there is a reason behind it i don't know yet but uh let's just go ahead and not add asynchronous at the moment so what we need to do in this case is also do something very similar to what we're doing in here navigator of blah blah push no not that one sorry this one navigator of context push name create or update note route so it may actually make sense to copy that code and let's go to in on tab and paste that i'm going to put a comma here so it breaks it down for me and in here what we're going to do is just to say arguments and we're going to pass the notes there okay so we're just saying that here's a note and go to that screen and pass that argument to it then when we go to the um create update note view this function gets called create or get existing node which in turn tries to grab that argument of type database node from our context using our get argument generic function which then goes to the modal route of that context and then grabs that argument so it's like three layers of extraction but that's that's quite fine now at least you have a generic function to grab your arguments okay so i'm going to press command s it might be good to do a hot reload sorry hot restart just because we've done quite a bit of changing so i'm going to delete these two nodes like that and then i'm gonna press the plus button let's just in here i'm gonna say my note number one i'm gonna go back and then i'm gonna press press and i'm just gonna say my note number two now i have my note number one and two in here then i'm now gonna test that to see that we can actually go and edit an existing note all right so i'm gonna go to my note number one and tap on it and now i can see i actually went to our notes and it says it still says new notes and maybe that's okay we could just leave it like that we could update the text maybe later that's that's fine but at least i can see the text so i'm now going to change actually this my new note sorry my note 1 to my note 3 and go back and i can see now i have my note 2 and 3. so this is a really good sign because that means that updating an existing note is actually working and we're not creating a new note because otherwise that note would have appeared in this list so i'm going to go to this new note 3 and then change it to one as well so now you see it gets updated all right perfect we got updating working and it was quite a breeze to be honest with you if you ask me so well done um what we need now is to make sure we don't lose our code so let's go as we usually do at the end of every chapter and we're gonna go commit and tag our code okay i'm gonna change the screen layout and i'm then going to increase the size of the screen so you see what i'm doing a little bit better let's go to our terminal and if you look at oops if you look at um i think it's was it command k yeah let's look at our git log and you see the last uh commit that we did was step 16 and also your tags the last tag was also step 16 okay let's go and commit now as maybe before that let's have a look at status and a bit has changed modified modified deleted it thinks that this file was deleted though it really wasn't um it was just renamed so um that's unfortunate that it marked it as deleted that's okay though but a little bit unfortunate there there are ways of doing that so that git actually understands that you rename the file but i can see that visual studio code wasn't able to actually mark that as rename and it also it just marked it basically was marked as deleted but that's okay we can live with that so let's just say git add all and let's just say then git commit step 17 all right and then we just say git push so we push all our changes and let's do a git status to make sure we didn't leave any files behind and we haven't so in here we're then going to say get tag step 17 as well and push our tags okay so that part is now done we've done our updating of existing notes and that's fantastic so as is tradition for every chapter in this course we always talk about what we when we need to work on in the coming chapter so we have a little bit of a problem in our source code at the moment and that is inside our node service so i'm going to get rid of this bottom bar here and go to node service and you can see in our node service we're exposing a functionality here called gets all nodes actually i don't think we're using this get all notes we're just using all notes stream and um let's see where that is here all notes stream and that is just reading the notes stream controllers stream and and uh that is coming from here you can see from our notes and that notes is being populated inside let's see get all nodes remove we have here so you see we are at the moment reading all notes and we're just exposing them to the outside world but wait a minute our application has the concept of users so so if we if we now log out of the application and log back in with another user then that new user is going to see my notes because there is nowhere inside this node service that we have a concept of a user like we're not actually filtering these things out and exposing only relevant data to the user okay so we need to fix that it's very serious uh it's not a bug it's actually something that i've intentionally left until this point because yeah we didn't have to handle that it was just more fun to work with the ui of the application but we have to be very conscious about these little things that we haven't implemented and that's exactly what we're gonna do and fix in the next chapter so i'll see you there hello everyone and welcome to chapter 35 of the swati course in the previous chapter as you saw we started talking about how we can update an existing node in the node list and we refactored our new node view as it was called before to become i believe create update node view and this node view is now able to do two things either create a new node or update an existing one so we didn't create a whole new view just to be able to update an existing node so that went really fine and however as i mentioned at the end of the previous chapter we have a little bit of a problem with our node service in that right now node service doesn't really take into consideration which users logged into the application and hence it cannot return relevant nodes for that particular user so what the node service at the moment is doing is just fetching all the nodes from the database and returning it to the current user this is going to cause an issue in that when we log in with one user we're going to see all the nodes in the system and when we log out with a user and log in with a completely new user we're again going to see all the notes that are stored in the note server so we have to fix that in this chapter before we get started with that we have a little bit of a problem with our updating and this is a bug that's been inside the application for a while since we basically created our cloud service and we have to fix that so let's have a look at what this bug actually is before i can before we go on so i'm going to put scrcpy in here and i'm going to put visual studio code in here as well all right so i hope you can see the screen so here right now we have um maybe i don't have to hope for it i could just bring the screen to be a little bit bigger so if you look in scr cpy right now we have two my note number two and that is exactly the box so let's go in here and to the first one and i'm just gonna say my note number one oops and go out and everything looks fine right now it's just because we are updating our local cache as well so things are looking good however if you do a hot restart of the application and my scr cpy just died so that's okay i can live with that it's a free software so as your cpy and and i can see now i've lost actually my debug command of scrcpy as well so i'm gonna restart the application but what is going to happen now is as you'll soon see is we have a little bit of a problem with our updates note functionality so you can see now that i now that i restarted the application all of a sudden both notes were changed to my notes number one and that's not that's not correct that's because there's a bug inside the application so how it's manifest manifesting itself is that when you update a note locally it looks fine but if you do a hot restart excuse me then it's gonna be tripping like it is tripping right now and the bug is right here i don't know if you can notice that excuse me i don't know if you can notice that but we have this call to the update function however we are not actually telling and this is also by the way this is inside node services dart inside the update node function in here you can see we're issuing a query to sqlite and we're saying update the nodes table and set the text to this text all right and that's exactly what sqlite is doing it's going through all the rows inside the note table and updating their text column with the given text so what we missed in there is a where argument so we're not telling sqlite right now which row to update so it's updating all the rows okay so we need to fix that as a matter of urgency so let's go in here and say we have now let's see this is our update and right after the creation of this dictionary we're going to say a were and we're going to say the id field of that column that we want to update or sorry the id field of the row or note that we want to update is going to be equal to something and where args are going to be equal to our nodes id so i need you to also write this code the way i've written it here so now if you say my note number one and i go in here and i say minor number two then it's going to do the right thing so if you do a hot restart then you can see that the notes are actually populated correctly okay i'm not going to do a hot restart just because i know scr cpy may crash again and i have to restart the whole process so i don't want to waste your time with that and that's why i'm not gonna do a hot restart but this should work okay sorry again okay um now back to what we were working on um or back to what the main goal of this chapter is so let's have a look at how we can fix the problem with our user server with our node service if you go here not being able to return relevant nodes except it's returning all the nodes so i believe it's inside node service right here oh we were there already sorry about that so we have our node service and you can see at the moment when we say here notes this is happening inside uh cache all cache notes which is you can see it's reading all the notes from the database using get all notes putting it inside putting it sorry you couldn't see that cache notes is reading all the notes and then putting them inside the local local variable and also populating the stream controller with that okay but what we need to do is need is that we need to make sure that the current user is saved somewhere inside this note service so that note service knows that okay here's the current user whenever i return all my notes to the call site using this all nodes functionality in here i need to actually filter out the notes inside that list to make sure only relevant notes that were created by that current user are returned from this stream okay so what we need then is to kind of keep hold of some sort of a current user in our um in our service inside this uh node service so let's go ahead and do that let's go actually define our um database user in here and we say this is optional and it's equal to user however we always want to make sure that that user is set before you actually grab a list of notes okay so this is the expectation of this note server so the note server says that if you want to be able to read all the notes the way you're doing it as clean as you're doing it you also make sure that you've set this current user okay so if that if that expectation is not met we're going to throw an exception and we're going to call that exception user should be set before reading all nodes as the caption indicates we're going to go to our crowd exceptions which we have from before so let's find that crowd exceptions in the given folder is sorry yes in the given path that i've mentioned in the bottom of the screen lib services cross crowd exceptions and we're going to define a new exception called user should be set before reading all notes like this all right so please go ahead and define that as one of the exceptions in your application as well under crowd exceptions all right so what we need now is a way for us to be able to filter all the given nodes based on the current user so let's have a look at our all nodes at the moment here you see what we need is to ensure that this all nodes can actually filter uh the given nodes inside this stream and using some sort of filter functionality so what we have you can see a stream here let's say stream a stream has a function called where so what it does is that as you can see it has um it it allows you to grab the current content of that stream and then you can pass a test on that so you can say if this object is equal to this then do that and return this value otherwise return something else so it's kind of like a filtering mechanism on a string on a stream's value however our stream includes a list remember let's go back here in excuse me in here you can see we return a stream of a list of database nodes so what we want is a where clause that's two layers deep we want to be able to filter out and change the contents of this stream based on the current user and we need to then filter the list based on the current user's id and only return the database notes that are relevant for that user so this is a bit of a special case so for that we need to create our own function which is a manual like filter function on our on our stream okay so let's go ahead and do that so what we need to do in here and is to create a new file as you can see under lib extensions list filter so i'm going to go ahead and do that let's see if we already have some extensions so i can see under lib right now we have constants enum services utilities views but we don't have any extensions so the best way then to do that to create that filter the dart file is just right click on live and say new file and then i'm going to say extensions list filter. okay so then what we're going to do in here is to create an extension on our on our stream so let's go ahead and just say extension filter on stream of t so the reason i'm doing it like this is that so we can grab hold of the contents of that stream inside our extension okay so like if you did something like this that would still work but in here what we're saying is that we're extending any stream that has a value of t and in our filter function then we can access that t as you'll soon see okay so then we're going to say stream of a list of that object and we're going to call our function filter and in our filter function we want to grab another function that does a testing of the items so let's then say bool um function that grabs an item of that type so you can see now we're basically broken down the requirements of our filtering that is what's supposed to be two levels deep is now one level leap because our filter function passes t which is our database node to this where function okay so this doesn't exist at the moment but we're creating that okay so in here what we're going to say then is what we are going to do is we need to map our um stream and that will you can see it gives us the values so in here we get the items and in here then we say items where we pass that word clause in here and we say to list like this so and i can see in here actually we have a filter of t but our stream needs to have a list of t so then that's gonna fix the problem for us so in this case we're actually drilling down two levels deep inside the list okay so this is the function that we just created so it allows us to filter a stream of lists of something and then our where clause is going to get that something and should that something pass the test then it will be included in the final list so look i know this is complicated stuff but please pause the video think a little bit about it we have a stream containing a list of things now we want to stream of the list of the same thing as long as those things any individual thing passes a specific test which is specified using this work loss okay this is difficult i know it may be some it may be like so difficult for some users that you'll be like i don't get any of this i don't understand but you will just need to practice you need to just grab a hold of this code go go ahead and implement this on some other functionalities like a list of list of things and see okay if i have a list of lists of things how do i filter out that thing inside and it will finally click okay i know it's it's a bit complicated so we've done that now what we need now um is to set the current user in the node service as you can see right now we have get or create user functionality in our node service so let's go back to our node service and find that function get or create user and at the moment it just takes an email as the caption indicates we need a parameter inside this function that also says set as current user so when you get or create a user which we're at the moment doing i believe in our notes view so let's go in here notes notes view in here uh you see get or create a user so this is like the bare bone this is the actual very important part of our application where a user either is retrieved from the database the way he or she was or it's created and it just makes sense to make that user the current user at this point okay so let's go in our node service and let's change that functionality so i'm going to bring up my notes as well and let's add a parameter called set as current user right here going to put a comma there and let's just say um that this parameter is a boolean set as current user and we're going to set it to true by default all right so i need to do the same thing please so after doing that when we retrieve the user we're going to look at this parameter we're going to say if set as current user set as current user then we're going to set our own user to this user that we just retrieved from the database and also don't forget when you create this user and you also have to set the current user if that boolean flag is true so let's just say set as current user here as well then we're going to say user is created user so what we did here is we just said if we could retrieve that user from the database we and this boolean parameter is true then we set our own user to this user otherwise if we had to create that user and this parameter is true then we do the same thing we set this current user to the created user and if you're getting some errors in here saying that this underscore user cannot be found it's probably because you missed adding this a database user to your node service which is something i mentioned just before we moved on to creating that filter function okay or sorry before we created this exception all right that part is now done as well um now what we need to do is to do the actual filtering and and that is something that we need to do is uh you can see as a cache index change all nodes stream to filter for the current user and that's something we need to do in the all nodes function or sorry the getter so right here what we're going to say is i'm actually i think i'm going to change them yeah just let's leave it like this so i'm just going to say no stream controller and dot stream and right here we can use our filter function you see now visual studio code is like confused like oh there is no filter function on a stream but remember we actually added that ourselves so i'm going to get help from visual studio code and say command dot on mac or control dot on linux and windows and visual studio code and then it's gonna understand oh there is a filter function that you've defined on stream do you want me to import that and i'm gonna say yes please so now we have the filter remember filter then gets a note right and if i move my mouse over it now you can see that says oh you have a database note however our stream actually contains a list of database nodes and all of a sudden our filter gets one note at a time so this is the beauty of creating your own extensions so that you can drill down inside existing objects and grab what you need inside your application all right so in here what we need is to create a function then you remember this function has to return a boolean we haven't returned anything from here yet that's why we're getting an error so at the end of this function we need to return a volume so let's just say final current user is this user and if this current user is not null which is like the condition that we actually expect then we're going to do some code otherwise we need to throw our exception user should be said before okay so this is our expectation from the caller if you're reading all notes from this interface you need to make sure that the current user was set when you call this function so this needs to be true okay sorry this yeah you may not have seen the code but you could also argue that oh wait a minute if this is like the expectation of this interface that the current user should always be said before you read all notes then why don't you make that the default why don't you just do that and remove this function and always set the user as a default well the reason behind that is the current user has to be sent only when you're working with all nodes now this node service should be able to work like to update existing nodes or remove existing nodes it in those functionalities should still work if the current user is not set right because those functionalities are pure cross functions that say update a node with this id get a user with this id delete a node with this id etc etc they are not dependent on a current user however all nodes is dependent on the current user and it just makes sense to have this functionality in here that says set as current user that is defaulted to true so if you're using all nodes then it throws an exception if the current user is not set okay so that's my reasoning for having this as a parameter and not making it the default um behavior of this class all right so if current user was not null that's like the happy path so then we say we return this note it's not as long as its um user id is the same as the current user id so we say note a user id should be equal to current user dot id okay and remember we're not returning a note we're returning a boolean remember our filter function it has a where statement that has to return a boolean so we're not returning any nodes in here we're just checking is this node's use ready the same as that then do this okay so that should now be good to go so what we could do i know this may actually and break things now because i have some problems with scr cpy but you have to excuse me for that it's it's nothing that i have control over but since we've changed quite a lot of code uh i'm gonna now close all these screens at these tabs and i'm going to do a hot reload but this most probably is going to crash the scr cpy oh it didn't great thank god for that so we have our notes now how do we put this into test what we need to do is to log out and log in so i'm going to go to console firebase and let's go to our application which is my notes flutter project we have two authenticated users these two emails at the moment so right now i'm logged in with one of them i don't really know which one so i'm going to log out here so i'm then going to log in with pixeltab gmail.com foobarbas log in and i can see those email those um notes were under pixel tab so then i'm going to log out again and i'm going to log in with the other user like this toolbarbad and i'm going to then press the login button and i haven't yet verified my email so i will have to do that so let me just see if i can take care of that right now i'm going to then bring my email and go to and see if i can find this um verification email and i can't so i'm just gonna send send email verification and it's gonna send a new email verification to me all right i got the email verification and it looks like this so i'm just gonna click on that and i can see now it says your email has been verified okay so let me go to restart then and now that i've verified my email i'm going to try to log in with a user as oops this is register i want to go to login so here foo barbats and then log in and now i can see for my user i'm not seeing any notes but just to make sure i'm just going to create a new user and say this no sorry create a new node i'm going to say this node was created for van dot or just put my email in here like this okay i'm going to go back and i can see that the note is displayed here then what i'm going to do is just to log out of this user and log in with the other user just to make sure that that oh that was created by the other user is not displayed to this user okay and now we can log in and i can only see notes that were for this user so congratulations that was a lot of work that we did and that we did and uh the application seems to be working the way we've designed it so that's great job what we need to do now is just ensure that we we won't lose our code as is a tradition and so we need to commit our code and also tag our code okay so i'm gonna do some uh shuffling around here on the screens and i'm gonna increase the size of visual studio code so you see it better let's do git status and see what the status is we've modified two files and we've also added a whole new folder so i'm just gonna say git add all and if you look at our logs the previous step was step 17 now we have to commit our work and tag it as step 18 and if you look at our are your tags as well you should have step 17 here let's say git commit and i'm going to say step 18. here i'm gonna push these changes to remotes which in my case is github you may be using bitbucket or some other remote and less than tag as step 18 as well here and put your tags alright so that part is done now we have tagged and committed or code so if you say git status you should have nothing handling here to be committed all right wow fantastic so again as tradition is we always talk about what we need to mention in the next chapter what we're going to go through in the next chapter at the end of every chapter so up until this point we've been using our notes crot service and that's been working really good everything's been saved on the on the device however if you really think about it you've now learned how to work with crowd and that was my that was like one of my intentions at the beginning of this course i wanted to teach you about crud because it's one of the absolute most important things that any back-end developer or front-end developer such as flutter developer has to know about so i hope that you've learned that now however we have a big problem here and that is all our notes are saved locally in a sql like database and should anything go wrong for instance if if the users something happens to the user's telephone all that data is going to disappear so the user's notes may disappear and you may think well what's so wrong about that well if you're like me i use my notes like my the default notes application in macintosh and also on linux quite a lot so i store very very important information sometimes in my notes and you'd be surprised that the outline for this course i actually managed it all i managed all of that inside the notes application on my macintosh so i wrote the entire outline took many many hours and i would have been devastated if those notes disappeared for some reason or if my kids got a hold of my telephone and just removed the notes and there was no reason and then there was no way for me to grab those notes back again so what we need to do now is just ensure that we can store these nodes in some sort of a back end so that it's sitting in the cloud so we don't have to manage them locally and that's what we're going to use firebase for and we're going to start talking more and more about firebase storage from the beginning of next chapter so i hope you enjoyed this chapter and grab your refreshments coffee or tea or whatever you want some chocolates and i'll see you in the next chapter hello and welcome to chapter 36 of this flutter course in previous chapters we've been working with our quad service quite a lot and also we've been working with firebase authentication so far we've stored the user generated notes inside the crotch store which we're backing with a sqlite database and we've also made that cloud service kind of um aware of the currently logged in user so when a user logs in he or she can only see their own notes and when that user logs out and another user logs and then the previously created notes in the database aren't exposed to the new user so we've taken care of all those but we still have our notes only stored in a local storage and from this chapter on we're going to be working with actually moving away from storing the user data in a local database and instead going towards storing that inside firebase now when i was designing this course i was thinking about how i can introduce more and more concepts to to become a better software developer and a flutter developer and one of those absolutely crucial things was crud create read update and delete and um though firebase is a good way of doing that but firebase removes quite a lot of the logic that you otherwise need to understand to become a better developer so firebase has abstracted away the concept of crowd quite a lot and that you work with data in the cloud and you don't really know how that is being populated and where that is being populated so when i started designing the course i thought maybe okay we could have a look at storing data locally first to get a good grip of crud and then after that we now we understand how crop works and how those operations are performed at a low level on a database level then we can move away from it and go to a more abstract layer so this was a choice that i met early on when designing this course and it is definitely not like wasted time you now know how to work with sql light in your applications and you will probably be using sqlite more and more as you go on in your flutter development um career so i am i hope that you understand that we are we still have good use of uh sqlite and we've understood that but now it's time that we move away from our local storage and move to using um firebase instead so i want to bring up the caption for the next section of this chapter and that's uh that we're going to talk about cloud firestore so if i bring up my notes and go to that url that i provided right right there for you and bring it up here and you can see here in in here it says firestore is a flexible scalable a nosql cloud database to store and sync data um the way the way it works i mean you can go actually to this link that i've provided for you here and it tells you about how you can actually add cloud firestore to your application but i believe we've already done that so if i bring our um application also to the screen increase the size and we go to our pop special and we'll look at our dependencies we're at the moment using firebase core firebase auth and um in here also tells you you have to use cloud firestore so let's go in here and we can see we've already dragged in cloud firestore from one of the absolute absolute earliest chapters in this course we've already added this dependency to our application so you don't have to do this but if you don't have cloud firestore added to your application you may need to do that now by following the instructions in this link and if you've if you don't have it it's probably because you've missed one of the early chapters in this um course so we're going to be using the cloud firestore in order to store user generated data and in this case our nodes now you may be familiar with sql and nosql but what i mean what i can explain cloud fire stories is that you will have um two concepts that you need to understand um which are called um collections and the other ones are documents so whereas in traditional sql storage you will have hard dependencies and every uh table for instance when we design our sqlite database we actually have to design our tables with specific layouts inside the table so we have different fields we have foreign keys etc so that's like a typical sql relation relational database but when you go to node sql for instance firestore then things are more document based so for those of you who are doing backend development you already know about that for instance so um if you're using sequel light then things aren't document based as you would think um but when we go to firestore then you will have like a lot more looser data definition for your tables and for your documents basically so one document inside the same collection can contain two fields and the next document can contain three fields so that's a lot more open the way it is created with firestar so for the entirety of this course from this point on we're going to be dependent on firestore in order to use it to store user generated content which are notes in our case so let's now talk a little bit about production versus test mode um firebase as use firestore as you'll soon see it has um different ways of allowing you as a developer to interact with your database so and there is a thing called a test mode and another caller production mode and in test mode and what it means is that as you're developing your application which we are for instance at the moment then you may need to for instance open up your database um so that you can actually interact with it with your from your application without even authenticating a user for instance so even if a user is not authenticated you can actually issue some commands toward firestore in order to read data delete data and and change data so that's that's as you're developing your application while you're still working with your authentication but remember we've already nailed down the authentication so you cannot actually end up in the notes view or the notes list view which is embedded inside notes view if you forgot about that you cannot end up in there if you haven't authenticated and if you haven't verified your email address so we know that in our case we don't actually really need to use the test mode of our database with firestore we're kind of gonna immediately switch to production mode and what production mode is is for instance when you develop your firestore database as you'll soon see in this chapter as well um you will be able to add some more rules to the database so that unauthenticated access to the database is going to be denied and this is the kind of like model that we're going to be using in the rest of the this course and also almost at the end of this course we're also going to add some more rules to our firebase uh sorry firestore database so that we make it even more explicit who has access to what just know that there is a test mode and a production mode test mode is a bit looser in terms of um in terms of security but production mode is a little bit tighter in that case that it it just tries to make sure that on authenticated access to uh for instance a document so the user doesn't have access to are going to be rejected all right we've i've just noticed that i just mentioned a few things about rules and you may be wondering about what these rules actually are and what they actually mean so i've prepared the link here so i'm gonna see if i can actually open it on my computer as well so i can bring it to the screen here it is okay so these are the rules that i was talking about so you see if you're for instance a back-end developer like i am you will also be very familiar with deploying your application so if you're for instance django developer or node.js with express or whatever or flask developer then you are probably used to deploying your application to some sort of a cloud service and then you will also be responsible for specifying how users can interact with your backend and what rules are applied on what cases uh firebase since it is not like this traditional backend that you have to deploy yourself since it is a product that's already there and it's deployed it needs your help in order to understand its security rules so as you can see this is a typical firebase firestore configuration of a back-end and you can see in here it says the service is the firestore service and match these documents at these paths and also only allow read and write if the user is authenticated so if you're a django developer you already know about like requests you also get that you're in django so a request user will contain the currently logged in an authenticated user there so that this is very similar to that and i'm sorry if i'm talking a little bit about back-end development that's just because i'm trying to like make this connection for those of you who are back-end developers and trying to learn about firebase firestore if you're not a back-end developer just know that these security rules are there to help you they're there to help you secure your database because you see the way we've actually generated our application let's go to the source code and have a look at it a little bit and when we set up our uh firebase with the firebase cli and firestore cli there were some files that were generated for us automatically and they were inside this firebase option so i'm going to open that for us here and you can see some information in here as you can see for android application there is an api key app id messaging sender id project id and storage bucket if anybody gets hold of this information as you now are going to get hold of this information by watching this course you will actually be able to replicate this firebase options. in your own application with my api key app id and sender id and interact with the database that i'm in control of even though you personally don't have access to that database because that database is stored under my profile in firebase console so using this api key and app id you can interact with the database and it is only the security information it's only the um authentication information or the authentication rules that i specify in my firebase config that will then decide who has access to what so don't worry also about this i'm going to delete this firebase project actually by the time this course is released so i'm completely happy with this information being public and shown to you just so you see what i actually mean so just know that with various roles that we can define on our firebase firestore project we can specify who has access to what and based on what rules for instance if the user is authenticated or if that user id is actually present in that document's id field for instance so something like that okay um now what we're gonna do is actually start creating a um firestore database for our project so uh what i'm gonna do in here is i'm going to bring up safari and i'm gonna go to console firebase.com so i suggest that you do the same thing change the screen layout a little bit here so you see my screen better excuse me and then i'm gonna go to our minus flower project so i suggest that you do the same thing for your application all right so when we end up here then on the left hand side you'll see something called firestore database and i want you to click there and just ensure that you've selected the correct application in here as well you may have quite a few just like i do then what we'll need to do in here and it's just to say create database okay and as you can see this is now the screen that may look a little bit scary but it's completely fine and you can see there are two different modes specified here as we talked about production mode and then the other one is test mode in production mode the rules by excuse me the rules by default are quite um bad as you can see in here it says any document inside the database is unaccessible so or inaccessible inaccessible it says don't allow read or write because the condition is just false so and you can see it says all third party reads and rights will be denied but this is really not the um this is not how we are going to set up our firestore database we as i mentioned before we are going to tighten this up quite a lot in in the future but not just right now so i need you go into start in test mode and you'll get this absolutely beautiful um message saying in um the default security rules for test mode allows anyone with your database reference to view and remember database reference i mentioned that that's inside this firebase options so that's the reference that we're talking about okay so it may sound a little bit abstract but it's really not that difficult to understand so and it says edit and delete all your database from all the data in your database for the next 30 days so okay and you can see the rule that has been set up in here says allow read write if request time is less than blah blah blah so it's opening up your database basically for 30 days it's actually quite intelligent pretty nice okay so i need you to do that and remember we're gonna tighten this up soon okay and then you can see in here it says allow basically set up a location for where your data is going to be stored now there may be some sort of like um conflict of interest between like the legal portions of your business and also where you want to store your data and where you actually feel comfortable doing that but and gdpr definitely makes this even more complicated if you're living in europe so i mean even if you're living abroad gdpr makes things complicated some websites that are hosted in the us are still not accessible by users in the eu and this makes things a little bit complicated i'm i'm basically in sweden right now so i i prefer to use maybe a location that is um has something to do with europe and uh i can see europe west while sweden is kind of like in the middle so i'm just going to use europe west right now but again this isn't so so significant right now it could have some speed implications for application depending on where the server actually is so it's really good that firebase is giving you the option to choose the location of your firestore database so you may want to read more about this and you can press learn more in order to read more about this but i'm just going to pick europe west just because i believe it it could make more sense for me since i am located in sweden so choose a location that makes sense for you and then press the enable button wow that is a an absolutely horrific looking loading screen what that is i mean it's not even centered so that's okay firebase remember we're using firebase as a free service so i just want to make sure that everybody understands i'm very very thankful for having firebase because it's made life a lot easier for me even though i can create my own backends but i sometimes still prefer to use firebase so um just because it's so it's so easy to use so uh thank you so much any anybody who's working on firebase and providing us with free services um so so let's have a look in here um about in our rules so let me increase the size of the screen like this and perhaps also increase it like this so you see it better let me see if i can perhaps close the section to the left a little bit and i probably could actually have done that so i'm going to go back in here and press this button to close that section all right so what we need to do now is to as the caption indicates we're going to change the the security rules in our database and i change it so that we allow read and write if the user is authenticated um so we make sure you as you can see it says request off is not null so let's go ahead and change that so i'm gonna remove everything after request dot like this and you can see it gives you access to off path resource time method so i'm just going to say off is not null okay so you can actually bring it to the same line as well if you want to so after you've done that you can say allow read write if request auth is not all and that literally just means that people who are authenticated with our application and they have and they have a valid firebase user when they interact with the database are allowed to read and write read from and write to the database however remember this is database wide at the moment it says any document and we still haven't talked about documents so much but i'll tell you soon about that but any just imagine anything in your database can be read from and written to if the user is logged in and that's not so secure because that literally means that i as user one and you as user two have access to each other's documents okay even if the application itself is like segregating these two documents saying that oh you're user one i'm gonna just give you user ones documents but internally as a firebase user given our current security um rules you will have access to my documents even if the application's limiting your access just remember that okay so after you've done that i need you to please press the publish button so as you can see it says publish changes can take up to a minute to take effect and that's all right because we're going to actually take more than a minute before we jump into using these new rules in our application so okay now let's talk about collections here um and i've prepared a doc and a link there so let me see if i can find that link here as well so as you can see in here there is a good documentation that will talk a little bit about collections and documents and you could go through this um but i'm not gonna do that right now but just so you know here's the link at the bottom of the screen if you want to do that i'm going to talk about collections personally so you will understand it in my words so at this point what we need is just to go to our firebase database okay and what you'll see is a screen that kind of looks like this so it has your project name in here and then there is a button called start collection okay just imagine collection as its name indicates is a group of related objects objects could be you could interpret them as tables as you traditionally have in your relational databases such as sqlite um so a collection just imagine for instance if we say what does our application do our application stores nodes for all its users so user a has nodes user b has nodes but user c may not have nodes so the only thing our application is storing in in database right now is notes so that could be its own collection okay so we just create a collection called notes and in that collection we're gonna store all our notes okay so every user is going to have their own notes that's how we are going to do it in this course however you as a developer may just think i'm going to do it differently what i'm going to do is i'm going to create a new collection of notes for every user so user a is going to have a collection called user a notes user b is going to have user b notes or you may just assign create a collection with every user id so you remember we get a user identifier from firebase you may decide to you create a collection for every user based on their user id okay that's fine but if you're following along with this course i strongly suggest actually do it the way i'm doing especially if you if you if it's the first time you're doing this if it's if you've done this before you may just be comfortable with creating another type of collection then be my guest please go ahead but it might then be difficult for you later on to follow along with the course okay so those are collections so let's go ahead and um tap the start collection button in here um as you can see in here it says okay this collection is being created in the root path and just give me an id and here's a collection set of documents that contain data and in here it's storing a collection of users but remember we don't have to actually store users in our database firebase is already taking care of this i actually believe this is a bad example that they provided to ask people to say example collection of users because this kind of gives id idea to developers oh now i have to store my users here but those users are already stored at the firebase level okay so let's go and go ahead in here and just say we're storing nodes okay and we're just gonna say next and you can see in here now we're getting something called a document parent path notes and then it says a document id a collection must contain at least one document cloud firestore's unit of storage documents store your data as fields auto generate a document or the id or customize one if needed okay so that that brings us to what documents are um a document you could look at it as if you're if you know about uh sql from before if you followed along with what being and what we've been creating like when we looked at db browser for sql lite then we had these tables like user and notes these uh these are like the schemas of a document so as you can see here and here says every note is created this way it has an id it has a user id it has a text is synced with cloud remember all those fields and it has that's the schema in far in the firestore world those are documents so that entire notes schema is one document and every field in it then it can have a data type so those fields you may know them as columns from before when we created our own tables okay so if we go back into db browser you may not have this db browser for sql light open and that's completely fine we're not gonna actually work with it right now you may have you may even have like is toss that database in the trash and that's completely fine i just want to show you this um that when we created this node table or the node documents then we had different fields remember id user id text and those were the exact same things in here okay so if i if i go ahead and create a new console firebase and have a look at for instance my other uh firebase projects i can see i have a notes app and you can here see that um the way i had designed this uh in the beginning of this course is i had a collection and then every collection had documents in it that had text and then user id okay so that's what we're gonna do in here we're just gonna say a field of text and it's typed string and it has no value okay and then we're gonna add a new field in here and just call it use righty okay and then in here it has no value either and then a document id that we're just gonna auto generate okay so we just pretty much just created a new note okay with a random document id and it has a field of text and another field called user id great then i need you to press the save button and now you'll see here we have our notes collection and inside there we have a document that has these two fields okay so what you could do also is to delete either a collection or delete a a document so i'm just going to say delete document and start delete and as you can see now we have an empty collection called nodes i still find this a little bit peculiar that when we create a collection firebase forces us to create a document inside it like if i go and say start collection and then press the next button in here i can't actually save my empty collection and it says every let's see here a collection must contain at least one document so i'm not sure if that's actually true because you can see now we have a collection with no document so i'm not sure why that was created why that uh rule was set when you create a new collection but just know that it's not completely true so you can have a collection with no documents all right so now let's talk a little about streams of data if you remember from our application in if we go to our i think it's called uh node service here you remember that we have this stream of database nodes as a stream of list of database nodes and we call it all nodes in our application up to this point we've had to manage these streams manually in that we have to like go create a stream controller do this whole dance of um unlisten populate the stream controller with the nodes you'd be really really happy perhaps to hear that when we go to firebase and firestore we don't have to do any of this because firestore already has all of this built in in that when you for instance read all the documents inside this notes collection that will actually be a stream of those uh data points for you so no more stream controller and no more streams that you have to manage manually okay those will be exposed to your application using firestore so so as you saw and when i created this collection to begin with i created it with a note document that had a text and it had a user id field so our goal in this chapter and going forward is to make sure that every node has a text and it is actually linked to a firebase user using that user's user id okay so if we go to our application to our auth service so let's go to off and then auth service in here and remember we're using firebase auth provider so let's go in there and you can see that when we say create user with email and password for instance then this function returned something called user credential to us and user credential actually has quite a few properties you can see it has a credential and it has a user inside it of type user so if you go into that user you can see it has different properties like display name email email verified metadata phone number etc but this user also has something called a user's unique id which we actually need in order to store notes into our collect notes collection so and this is what i mean every document that we create is for instance going to be node some random id or something which we haven't decided yet and one of the fields let me actually see if i can resize uh this safari window so you see it better so it's going to have a text and the text is going to be generated by the user but it's going to also have a field called user id okay so in this user id field we actually need to store that user's gener firebase generated id in there okay and now going back to what we are doing with that user do you remember we're not actually um exposing the firebase user to our application and that's a great level of abstraction however we have a little bit of a problem in that right now our user has email and is email verified it doesn't actually have a unique id so our application is not going to be able to associate new notes with an auth user it's not going to be able to associate a new note with a user id okay so we need to fix that so i'm just going to go to my notes a little bit in here and what we need is to update our auth user as you can see in here so in auth user.dart file as i've opened in here and what we need is to add a new field which is a required field and we need to make that the id of that user okay so let's go ahead and do that now so i'm just going to go ahead and say final string and id so this field is not optional here you see every user that comes into our application should have an id and that's like the expectation that we have on our off users okay so i need you to go ahead and add that please here of user class as well let's then go in here and i'm going to add this um to um the required fields i can see visual studio code wasn't able to actually meet this required parameter i'm going to help visual studio code and do that i'm just going to say required this id and i need you to do the same thing please so now we have a problem in here in that our auth user in here doesn't have an id where we created from firebase user let's go and remedy that let's just say the id in here is the user uid remember this uh parameter that i uh talked to you about okay so that is now created and let me actually go to scrcpy i can see that visual studio code has a little bit of problem hot reloading right now so that's because probably the application wasn't in the foreground so that's fixed now talking about scr cpy it's perhaps a good idea for me to bring in crcpy here just to make sure that we're not bringing and breaking anything okay so so that's one change that we have to make to our auto user the other change that we have to make is to make sure that the email parameter of our user is not optional you see the way we are creating at the moment are um our application is that we've created the login process of a use email and password authentication so we don't have like facebook authentication or google authentication we only have username and password sorry email and password so given that condition we can be sure that every authenticated user in our application actually has an email address okay so let's go ahead and just say that email is not an optional field anymore and in here we're going to explicitly unwrap that email all right so that's another change that we made to our application so now that we've done that you can see flutter is not so happy with those changes saying that well yeah you broke something and it's our tests that have been broken so as you can see uh we need to make sure that id is actually included in our tests as well and since we're not actually creating a specific test for that user id we can just add a random id in here let's just say my id okay and i'm going to bring that and bring it down here as well so we have an id field in both cases of auth user inside our tests okay now we have another problem as you can see in the captions in our create update note view we are unwrapping the user's email and that's what this little orange views um folder is it's not red meaning that well yeah it's not an error but it's a warning so let's go to this create update note view and have a look at this uh field in here as you can see we're in inside the get a create or get existing note and we are unwrapping this email but right now the warning is saying what is it saying the uh uh asterisk will have no effect because the receiver can't be not try removing the asterisk operator and i need you to do that please we have another problem also we have another warning inside the notes of you and i believe we're doing something similar in the notes view so let's see if you can find a warning [Music] where is the warning i actually don't oh here we have the user email in here as well so i'm just going to remove the asterisk after that so i need you to do the same thing please okay now we're gonna get to the juicy parts of the uh cloud storage integration so i'm clean i'm basically removing all the file all the dart um tabs from here i'm actually not deleting the files i'm removing like that tab so it's a clean slate then what we need is to um create all our cloud storage exceptions you see if you remember from when we worked with our quad service which is a node service then we also had a file under the croth folder called crowd exceptions and in here we define all the different things that could go wrong when the user is working with our node service now that we're moving away from crud we need to have our new exceptions defined somewhere and and as you can see in the cache just like we had the crowd exceptions we're also going to have some exceptions thrown by our new fire firestore service which we haven't developed yet but we need to define those exceptions at least okay so what we need now is to go and create that file so i need you to please create a file under lib services cloud and then create that file as cloud storage exception so i'm going to do that as well so let's see i'm going to fold all the folders in here so we have lib services and then cloud you can see we don't have cloud at the moment so we do have services and we have off in there and crowd so i'm gonna right click on services and say new file and then in here i'm just gonna say cloud and then slash cloud storage exceptions.dart okay so after the creation of that file i'm going to remove the project explorer there as well what we need then is to define a super class for all our cl cloud exceptions if you remember from the crowd exceptions that we created in here all those exceptions were actually of type exception and that's one way of doing that however if you want to group your exceptions under one super exception and you could then handle them quite smoothly or better actually i would say in at the call site and so that basically is going to use inheritance and then you and we are going to create a new exception as you can see here called cloud storage exception and all our cloud exceptions are going to be of that type so makes grouping and catching these exceptions in the future a lot easier okay so let's go ahead and create our first exception it is called i can see it's called cloud storage exception so let's go ahead and say clouds and class cloud storage exception and implements exception okay and we're also going to create a constant constructor for it so it makes creating instance of this a lot easier and you could also basically say that this is um an immutable class meaning that this class and all its subclasses need to be immutable you could do that all right that's fine as well but usually exceptions aren't marked with this it's usually data classes that are marked with immutable so i'm not gonna do that right now okay that thing is done um now so that's the parent exception we should try not to throw that exception as it is we have to throw subclass subclasses of that exception okay now the first exception that we're going to define is could not create node exception i believe it's called yes and we're going to throw this in our to be written a class soon uh upon you trying to create a new note if firebase firestore is not able to actually create that note then we're gonna throw this error okay so i'm gonna then define that exception and you will need to type this then um i just brought it from my notes now also in this screen where we have all the notes displayed for a given user we may also not be able to retrieve all the notes for that user for instance if there is a network connection issue or whatever whatever other issues that may arise so we need to have an exception for that as well and that exception is called could not get all nodes exception okay so let's define that as well and it's written just like could not get all notes exceptions exception the next exception that we have to define is called a could not update nodes so we have create node exception get node exception and now we're on the u part of crot so you see the create part is a c in crud gets is r and now we're looking at you okay and that is uh could not update node exception so so we could say this is um you in crud and the get is r in crop and create a c in crud okay and so we have c r u and then we have to define d which is for delete infrared and that's exactly what we're going to do now so let's go define could not delete node exception all right so let's then say be in crop okay so now we have um three four uh exceptions defined and all of those exceptions are uh inheriting from cloud storage exception okay um now that we've talked about the exceptions we also have to talk about the actual cloud storage service you see we have our quad service at the moment which we've been working quite a lot with and we're very proud of it actually it's a lot of code in my implementation at least in here we have about 360 lines of code i mean it's not all code there there's also spaces there's like i think there are some annotations like immutable etc but there's quite a lot of code okay and there's a print statement in here which i actually have to remove okay so there's quite a lot of code and this is working with sql lite but we also need a service that works with firebase firestore so we need to create that service soon so just know that we are going to have crud in here which is going to talk with sqlite but we're moving actually away from it so let's then fix that um so let's go in here and have a look at our constants and if you look at our node servicing here and we have our constants in here we have routes and at the end of node service we have some constants defined right in this class or right in this dart file and some people may like this but i personally prefer to have my constants defined in separate files even though these constants are very related only to this file but just making them putting them in separate places just makes it easier to look at because these constants at the moment like hidden at the bottom very bottom of this file so let's go ahead and define our constants so let's have a look at the path it's going to be in services cloud and then cloud storage constants on the services now we have cloud and under cloud we have cloud storage exceptions i think exceptions yep now we have to define cloud storage constants so new file cloud storage constants dart and i'm going to go to my notes [Music] constants all right now if you remember from our note series we define like the tables and excuse me and we defined the tables the columns and and even the format of creating new tables we don't really need these all we need are these two fields as you remember the text and also we need a field for user id like this so let's define these let's just say owner user id so let's go in here and say const increase the size owner user id is just user id like this and then we're gonna say const text field name excuse me so i need you to define these two fields as well for your application okay so let's go back to the original font size in there so now that we've defined that if you remember from our note service we had these beautiful classes in here a call called a database node and a database user now given that we're moving away from storing things and notes inside the sqlite database and we're moving to towards a firestore um databases we actually don't need a database user anymore but we do need some sort of a class that represents these documents that we're going to create in here okay and what we are going to call that is called a cloud node so let's go ahead you see here is called a database node so then you kind of know that it is a local database maybe you could rename this local database node if you want to but i'm not going to do that simply because we're moving away from this so what's the point of refactoring it so i'm going to close node service so then let's go ahead and create a new file called cloud note dart under services lib services cloud and i'm going to call it cloud underscore node.dark in here now what we need to do is actually implement cloud nodes excuse me so what a cloud node actually is going to contain there are three properties that the cloud node has to contain and they're namely the actual identifier of that node and i apologize i actually have to put myself into do not disturb so so there are three things a cloud node has to contain one is the actual like primary key of that note in our database every document that is generated by firebase is going to have a unique id if you're coming from like backend development then you're already familiar with this for instance django has this idea of a pk which is primary key you can also read it as id so everything that's stored in the database has some sort of a primary key firestore is no different so every document that is created inside a firestore database is also going to have a primary key okay so that's the first property that our cloud node is going to contain the other two are very familiar because you saw here in the documents we're gonna have a text field and the other one is like the owner user id so there are three fields that we have to add to our class so let's go ahead and do that let's just say um if i can type here so class sorry i have a microphone right in front of my face like it's blocking my keyboard so that's sometimes that's why i have to like look like this just to find my keyboard so let's say cloud node um and inside our cloud node let's define these three properties so let's just say final string document id okay and i'm going to copy the string here as well and say owner user id and then we're going to say text okay help from visual studio code to implement the constructor and um in here then i'm going to say this is a constant constructor okay as i said you could actually go and define this as immutable which i actually prefer in this case to be honest with you i hadn't i hadn't planned to make this immutable but i think actually makes sense if it's a cloud node then let's just say it's immutable okay so that's that's the first part and i also know that we need to make these required parameters so let's go ahead and do that let's just say required before all of these parameters okay so that they're actually required named parameters that are not optional basically okay that's that if you look at how our database nodes let's see if we can find database node inside nodes service so let's have a look at database node do you remember that we had these fields but we're pretty much never calling this database nodes a constructor we're always using this thing database node from row and this is basically the object you just see this map is the object that we're reading from our sqlite database and crew and then we're internally creating instances of our database node from that object okay so this kind of map is what you will also receive from firestore however it's going to be wrapped inside something called a query document snapshot so it's just a wrapper around your data so let's go ahead in here and and what we're going to say is if you just type query document snapshot then visual studio code is going to import this automatically for you okay so then it should be imported in here so that's great and also we need our um cloud storage constants so let's go and import those as well so let's just say package and my nodes and we have uh what do we have where is this stored inside services cloud so services cloud constant or sorry cloud storage constants so you need cloud firestore dart and then your constants as well let's go ahead and create kind of like a constructor that we are going to call from snapshot and this constructor is going to allow firestore to give us a snapshot of it and cloud nodes and then we're going to create an instance of our cloud node from that okay so let's just say cloud node from from snapshot and parameter is going to be query document snapshot that has that map that we actually need like this and we're going to call it snapshot like that okay so now you can see that we're getting some errors from um from dart saying all final variables need to be initialized and a function body must be provided okay we're going to fix it soon so this is this is the um signature of your function then in here your job now is to make sure that all your fields are initialized so let's let's just say if i can type again document id it comes from our snapshot id that's a property that is stored on this at the snapshot level so you can get that id okay and what we're going to say is that we have an owner user id that we also have to fill in so that comes from the snapshot uh snap shot data and in there then we have to say the owner user id field name let's see owner user id under user id let's call this field name so sorry about that let's go back to the cloud storage constants and fix this to say owner user id field name actually okay so we missed that but that's okay it's just a naming change so then we're gonna say owner user id field name so that's for the owner user id and we're going to get the text which is equal to snapshot dot data and text field name as string okay so what we have is a beautiful cloud node immutable class with a constant constructor and also we get this snapshot um query document snapshot from firestore soon and we can create instances of our cloud nodes as you'll soon see all right now what we need um is to create our new cloud firestore service so this is like the beginning of moving away from cloud storage into firestore so this is actually very exciting and a little bit um a little bit intimidating maybe at first because well we kind of have to like redo quite a lot of work but given that firestore provides you with pretty much all the tools that you need as you'll soon see the implementations of the functions that we're gonna that we're gonna do are so minimal because the base is there fire stores already provided the base we just have to hook into it and grab the data write the data etc so so let's close all these tabs that we have at the moment excuse me and let's go to this um services cloud and create our new firebase cloud storage dart file firebase cloud storage dart all right so i'm actually going to do that as well so firebase cloud storage in my notes all right so let's go ahead and say we have a new class called firebase cloud storage like that at the moment it doesn't do really anything but what we need to do uh is to make uh make this a shared instance and i'm gonna bring the caption for that and if you remember we've already made our node service a a singleton so let's go back to our node service command p on macintosh and visual studio code or control p in windows and linux to bring up this search files by name field and i'm just going to say note service if you remember inside note service i think at the top we had this pattern for creating a singleton do you remember this right so we kind of need or sorry this part we kind of need the same thing not kind of actually pretty much exactly the same thing except for this part because this talks with a stream controller so i find this pattern of creating singletons in dart still quite hacky i think i've mentioned this before when we created the node service but it's something that we have to do so make sure our firebase cloud storage is actually a singleton okay so i'm gonna bring that code from my notes because i don't think it's actually worth writing this and it's not worth your time or my time but this is what you need to create so what is happening in here is that we have a private constructor then we're going to create a factory constructor which is the default constructor of our of our class firebase cloud storage right here and that is going to talk with a static final field which in turn calls this private initializer so in um in other languages like swift and rust it's it's a lot easier to create a singleton but this is a pattern you have to do so first create a private constructor then create a factory constructor that talks with a static final which in turn talks with the private constructor okay okay after you've taken care of that what we need to do is to grab all our notes from our cloud storage okay so let's just go ahead after this factory constructor we're gonna expose a field as the note as the caption at the bottom of the screen in the case call notes so i'm just going to say notes equal to we're just going to say firebase and firestore and it's going to auto import it for me so this is not a strange thing anymore to you as well and then i'm just going to say our own instance and then excuse me a collection called notes quotes as well okay so this is how you actually talk with a firestore so you can see that the signature of this collection is actually returning use something called a collection reference and you will soon see how we can extract our actual notes from this collection all right and also remember this isn't gonna work if you haven't actually created your notes collection so if you haven't done that if you forgot to do that please go ahead excuse me to go ahead and do that right now so the first thing we need to do is to create a function for creating new nodes all right excuse me so let's go ahead um into our project and create a function as the caption indicates i'm going to say void create new nodes in here and then we're going to say we need a an owner id so required string owner user id i believe we call it and then it's an async function okay and then in here since you have like a stream or a read write stream uh of all your notes and that's what this uh collection reference means it's it's not only a stream that you can read from but also it's a stream you can write to that's why that's why it's not called a stream okay because the stream is like you try to read only from it so and in here what we're gonna do is going to say notes add and you can see it literally says give me a map or a dictionary or however you want to call it an object that has keys and values what do you want me to store in a database and that's what nosql kind of means in here is document based it's it has no real structure of what you're adding everything that you add in here is going to be packaged into a document that is going to be stored in here with the fields and the values that you specified in here okay so let's go ahead and say we provide you with a with a document in here and the first field is owner user id field name and that's gonna auto import it from our constants from before remember and in here the value of this is going to be the owner user id and the text field text field name is just going to be an empty note for now okay and remember this is an async asynchronous function which returns a future of a document reference just like we have our collection reference in here but we actually don't want its results right now at least so we're just gonna wait on it so don't forget that weight because without doing the weight this function is not actually going to be invoked wow okay um what we need to do now then is to go to the next item excuse me which is getting notes by user id so the signature is going to be it's going to return an i of cloud note you given a user id so as we said every every node we store in our database uh is gonna have these two fields an owner and a text field so now what we want is to grab all the nodes for a specific user okay so let's go ahead and do that so it's called um get notes and it's quite a meaty function actually i can see in here so let's go ahead and do that right now let's say future of iterable um of cloud nodes and i think we have to import cloud node as well so pressing this button imports this for me if you're getting some errors it's probably because your editor hasn't been able to find cloud nodes so and then we're going to say get notes and a required parameter in here under user id okay and it's an asynchronous function so like that so what we're going to do then is to um a weights uh on our on our notes in here you see we can actually retrieve notes from our notes collection in here by saying notes where so we're gonna do a search inside the notes uh collection reference and that and you do that using the where clause okay and these things could actually increa like create an exception i believe the word clause could actually throw an exception whether it was this one it's not documenting here but i do believe that it could actually create an exception so let's go ahead and catch this so let's just say try we're gonna try and then should anything happen in here uh we're just gonna throw and could not get all nodes exception and this is going to auto import that from our previous code so i i shouldn't explain this over and over again you know already how that works okay so now that we have that we have a try and catch statement in there so let's just say we await on the notes and we say uh where clause and the word clause is going to say okay what is the field that you want to do your work search on and we want to search for all notes that are for this owner user id so let's just say owner user id field name should be equal to you see that's the parameter is equal to owner user id like that okay waiting on it you see sorry after doing a word this gives you a query but then you need to actually execute this query and you do that using its get function and you see it returns and let me see gets if i move my mouse over you see it returns a future of a query snapshot with all the objects that firestore could retrieve from the database okay so we have to get um what we do then is to do then that's that's how we work with future so event clause of the future allows you to return it what it does is it returns the value of that future to you and it allows you to return either a synchronous value inside the then function or you could actually return another future those who are familiar with node.js or just javascript in general or even swift they're familiar with how promises and how futures work so this is your chance of actually returning a value given this future that is returned to you okay so we're going to call this basically value at the moment and if i move my mouse over this you can see it says a query snapshot of these um potentially written red documents so in here what we're going to do is say docs which is all the documents that could be read and we're going to map all those and you can see in here if i call this doc if i move my mouse over it so it creates document snapshot whereas this one was a query snapshot this one is a query document snapshot of those fields okay so let's go in here and what we're going to do is to say we return inside this return a cloud node and we have these three fields okay we have the document id owner user id and the text so it's our chance basically to create an instance of our cloud node right now i'm gonna put the columns here so we get the formatting a little bit better and what we need to do is to get the document id and the way to do that is this dock has an id in here you can see it's a string so and the other one is to dock and then we have the data and let's just say owner user id field name and that's a string and in here we're gonna say then a doc data and we say text field name as a string now remember this looks very familiar where have we done this before yeah we've done this in cloud notes from snapshot and don't worry we're actually gonna use that function as soon we're gonna remove this return statement the way it's written but let's just write it like this right now okay so it's easier to understand wow all right um i think i think that should be it and so we have that excuse me and um yeah i believe i believe this is going to cover it for us right now so not much more to explain about this to be honest so we could also put a comma here to make the code a little bit more readable and we have the value then return and what we don't have to be honest with you here is this return statement in here or actually we created this like this so yeah it's an arrow function so we don't have to have a special return statement but if you don't like this kind of an arrow function you can grab your code that you've written up to this point like this and create curly brackets in here and instead use this syntax to say return instead okay so it kind of depends on what you prefer um i don't have a preference and i could use an error function the way it is so i'm just going to leave it like this okay and remember we're at the moment awaiting on this but we're not returning it so let's just return so this is all basically just a fancy way of us excuse me communicating with firebase firestore and reading documents and there's so much to explain that i can't go through all of these but i really suggest that you play with these functions yourself read the documentations and see why is it that i'm using where and then get so uh for that you need to read all the documentations that come with these functions so you understand them better okay um so that's getting notes by user id now what we need is also um [Music] what we need is the ability for us to be able to provide our notes list in here with a stream of notes for that particular user okay so um as you as you know now in our note service the way we have it is we are exposing this stream of list of database node and that's what we kind of also need to do with our firebase cloud storage like have a function that our nodes list excuse me can't subscribe to and read all the available nodes for that given user so let's go ahead and do that let's just call it a stream iterable and i have that function signature so i don't think i should actually write it manually but you may need to write it so so that's a function signature okay and in here what we're going to say is that we're going to go to our notes collection in here and get all the available snapshots let's see we have our notes and then we have our snapshots and we're gonna map that and let's just say yep gonna get our documents inside that snapshot and then we're gonna map that like that and let's just call it doc and in here we're gonna create a cloud note from snapshots of that doc like that and then in here we're going to say where that's our note and then we're going to say the notes owner user id i'm gonna actually write this and then i'm gonna tell you what i'm basically doing because there's quite a lot of code in here and like pausing to describe every little bit of this code could actually make it look more complicated than it is so and i'm just gonna then say owner user id okay but a semicolon there wait a minute this ends there and then a semicolon there yeah so let's see what is happening in here so this looks actually quite intimidating to look at but it's a very simple piece of code so what we're doing in here is if you want to grab a stream of data as it is evolving you want to be able to subscribe to all the changes happening to it then you need to use something called the snapshots as you can see this is a stream of query snapshot whereas where is a query itself okay and then get is a future so it just the get one literally takes a snapshot at that point in time and returns it to you but if you want to like keep hold of like if you want to be updated about all the changes live as they're happening to your data in the notes collection then you need to subscribe to the snapshots that's what we're doing okay so that's that first part with snapshots so we're literally saying that we want to see all the changes as they're happening live okay then it says okay i will give you all the changes that are happening live and that comes inside the query snapshot remember query snapshot from here remember query here oops inside the get so after this point is it's literally what we did in the get notes it's saying that okay here is a query snapshot and then we're saying okay there are documents in there and that's exactly what we're doing in here there's documents in the query snapshot and then we're mapping every document to a cloud note all right and then we're putting and where clause at the end that says we're only interested in notes whose u owner user id is the owner user id provided in here so without this word clause we're literally exposing all the notes um to the current user for all users in the system so that word clause is very important okay so and this work clause as you can as you can see it is actually inside flutter bin lip core iterable so that's nothing that is it's not a function that firestore has provided for us okay wow that was that was a lot of information okay let's go ahead and talk about updating you notes sorry updating existing notes so as we talked about it before if you have a note and you tap on it the way it works in our application right now is i can tap on this node and go and change its text like 22 and come back out and now it's changed to 22 okay so we need to also expose this functionality excuse me in inside our firebase cloud storage um as well so the function is going to be update node and it's going to take two parameters document id and a text so let's just say it's going to be a future of void and we're going to call it update node two parameters in here which are required i'm going to say required string and document id and then required string text and let's make this an async function all right then what we're going to do is we're going to put a try and catch in here in case we can't update the notes and then here we're just going to say throw could not update note exception okay and you may actually ignore this e if you want to as well so you could just do like this or you could just yeah i think actually we can't do an empty cache catch so you may do like this if you prefer but i prefer to do it like this all right and i can see that the formatting is a little bit messed up in here so i'm going to put a comma in there and inside the try statement in here now what we need to do is to go to our collections again in here and let's just say we get a doc you can see it says okay what is the path of that doc and we're going to say the document id is a path and then let's then go ahead and say um dot update and it says okay what is the actual update and inside the update what we're gonna do is gonna say text field name is this text all right so this may look a little bit crypt now also we have to wait on it may look a little bit cryptic in the what is doc dock id remember inside this function in here it says give me the path you see this parameter path and what we said is that inside the notes collection every document is going to have an identifier so we actually are going to go with the document id which we instantiated in here do you remember doc id is going to go into our cloud node document id so that's the path is notes slash that document id so that's how far firebase firestore it called and basically keeps hold of its paths it's the the path is in this case if i create a collection you see it says oh the collection is being created in the root folder and it has a collection id which in our case is called notes and we refer to it here so we've already constructed the notes path and every document inside it has its own id so it's going to be slash notes slash document id all right so i hope and i'd explain it for you let's now talk about deleting notes um so deleting notes actually very easy as well so we don't have to do so much with deleting nodes so it's very similar to updating nodes and we're just going to go ahead and use document id for deleting notes so as the caption indicates create a new feature of void in here and we're going to say delete node and we're going to go ahead and use a required string parameter called document id it sync and let's just do a try cache in here in case we can't delete the document and then we're going to say throw could not no notes exception i believe it's called yeah inside the try statement in here we are going to say notes doc with that document id all right and then we're just going to say delete i remember i believe this is actually future void so let's just wait on it all right so that's really all you have to do for delete so there's no magic in that it's very similar to update note except that it's not taking care of any like fields or anything like that wow huge huge chapter we've talked a lot about now uh about firestore and firebase storage so thank you so much for for sticking with me throughout this chapter and but if you remember i mean if you look at what we've done is not so much code it's 68 lines of code for me it may be less for you if you haven't done all these extra commas in here so maybe like 60 but there's a lot of new concepts so i thought that i had to i took the liberty of maybe even over explaining things but i think in the beginning it's very important just to understand how everything works um okay so great job we've done what we promised to do in this chapter we have actually tested to make sure that this is this is working we're gonna do this in the next chapter but as it's tradition we're gonna make sure that our work is committed to our uh github repository or bitbucket wherever you're using your uh or wherever you're hosting your git project so let's go ahead and do that i want to change the screen um layout a little bit i'm going to get rid of scrcpy oops and i'm going to close the screen make this bigger in this uh view and then i'm going to go to terminal okay excuse me let's have a look at our status there's quite a bit modified in here and also we've added a whole new folder so i'm just going to say git add all and let's have a look at our log the previous commit was step 18 and let's have a look at our tags i can see step 18 here as well let's commit now let's say let's say step 19 excuse me again and then we have commits and we've committed and let's push those changes let's also tag and say step 19 in here okay and let's push our tags as well all right that's that as again is tradition at the end of every chapter we'll talk about what we have to discuss in the next chapter and as you can see it says uh we need to start using our new service instead of sqlite database so that's a little bit of a um like a turning point in our whole uh course in that we're gonna like toss our local storage and go away from that and start using our firebase cloud storage and so uh it's it's i think the next chapter is actually one of the most exciting chapters excuse me in this whole course so grab some refreshments if you want to and i'll see you there hello everyone and welcome to chapter 37 of this flutter course as you've seen in previous chapters we've started to move away from our local database storage and that was on sqlite and we started going more and more towards using firestore databases that are hosted by firebase so that was a very exciting point in our um in this course basically and for me as well as the as your instructor to go over to a cloud storage rather than using local uh storage and you see we used crud and as i mentioned in the previous chapter i really wanted to introduce you to crowd because it's such an important part of software development that you will sooner or later need to use crowd storage locally on your computer on your applications so um that was basically done on purpose so we first talked about local storage and then we move away from it and simply because uh even firebase in itself is some sort of a crud storage not some sort of it is crud but it is stored on the cloud and concepts of crop would have been a lot bit more difficult for me to explain to you had me not first implemented implemented them locally so um in the previous chapter we prepared our service which we i will bring the code here so we can have a look we we actually called it let's see it's inside our services cloud we call it firebase cloud storage right here and um we also talked about how we can basically start integrating in this firebase cloud search in our application and this is the chapter that we're gonna um make those plans concrete okay if you follow the chapters from the beginning chronologically in this course you'll know that what i like to do when i try to refactor things is to cut things from the source and by that i mean now we want to get rid of our local crud storage and what i like to do as a strategy is to go to uh the application and like either comment out that entire piece of code which has to do with our note service and the crowd exceptions or either we cut it out completely or we commented out okay so let's go ahead and deal with that now so i'm gonna change the screen layout a little bit here and i'm then gonna go into our notes service so please go to the note service and select the entire code in here and comment it out so that's for note service and then we're also going to go to our i'm going to save this file and then we're going to go to crowd exceptions select the entire content and comment it out please so that's that um another thing that we need to take care of is um inside our new firebase cloud storage inside uh get's notes what we forgot to do is where i actually didn't forget to do i intentionally left it like this so that we could get the basic idea is as you can see here we we are inside this uh get notes function as the caption indicates at the bottom of the screen we are returning an instance of our cloud node use using its constructor its default constructor however if you remember from this cloud node snapshot we have a convenient constructor that can create an instance of our cloud node using a document snapshot and that's exactly what we're getting in here you see query document snapshot but we're not using that convenient constructor and that's exactly what we're going to fix right now so excuse me let's go in here where we have the dock and i'm going to change this code to go from a normal function to an error function and then in here i'm gonna say we return a cloud node from snapshot of that dock okay just like that i press s to save this file command sorry and you can also remove that comma at the end so you either leave it like this with a comma at the end so it becomes multi-line or you remove the comma like i do in here and it just becomes one line all right okay that part is done now what we need to do um is to be inside this firebase cloud storage and you can see in here inside the functionality uh sorry inside the create new node at the moment we're saying void so we're not returning the node that we're actually creating and we need to fix this so we need to actually create the new new node and return it so let's go in here and i'm just going to say final make the code a little bit bigger final document is equal to a weight on this and if you look at your document now you can see it is a document actually you may not be able to see it now you can see it probably it is a document reference okay so it's a reference as its name indicates is not the snapshot in order to get the snapshot we need to just issue the get function on it so let's just say final fetched note is a wait on this document get and you'll see now fetch note is the actual snapshot that will contain the data of that document all right so in here we will just return a cloud node like this or let's see cloud node with these parameters the document id is going to be the fetched note id the owner user user id is provided to our function already and the text is just going to be empty like this and also make sure that uh in here we don't return void except we return a future of cloud nodes okay so save your file after that and this part's also done okay um now we need to make sure just i'm just gonna close uh all these tabs and as the caption indicates we're gonna go to our create update notes view and fix that up so it can talk with our new service which is the cloud firebase storage i think we call it firebase cloud storage sorry about that so i'm going to press command p in visual studio code on mac or control p and linux and windows and then just say create what's it called create update node view okay and here as the caption indicates we need to import three things our cloud node dart file the cloud storage exceptions dark file and the firebase cloud storage dart files so those are at the moment inside the um let's see they're inside services cloud folder so i'm going to go in here i'm just going to say import package my nodes and then services cloud so we have first cloud node so let's import that i'm going to copy this path and then use it again to import cloud storage exceptions like that and then we also need cloud what's it called firebase cloud storage like that so that's you will need to also do these three imports if you haven't called your application my notes then this package is going to be different it's going to be packaged the name of your application and then services etc etc okay okay um the next thing that we have to do as you can see in the captions here we need to make sure that our create update node views state which is right here which at the moment contains our node service as its node service it has to move towards using the firebase cloud storage so i'm going to go to my notes as well in here just to make sure i'm giving you all the information that you need so let's change our node service in here and call it now firebase cloud storage and that's the service okay and in your init function then you need to also make sure that we get the singleton instance of our firebase cloud storage in the init state function all right also remember this note now is not a database note anymore but it's actually a cloud node so let's call that cloud node as well all right and and now we can see we have an unused import in here so i'm just going to remove that since we don't need that unused import then the next thing we need to do is as a caption in the case we have to go to create or get existing node and we have to make sure that it works with the cloud storage so let's go in here perfect so in here we're not going to return a database node anymore and we're going to say it returns a cloud node and here we expect a parameter of type cloud nodes optionally that can be passed to our routes and here we're not going to be working with you see here we were working with database users before because our application was actually creating new users in the local database and associating notes with those users thankfully that now that we're going to now that we're using firestore um database we don't have to play with users anymore because remember users are already managed by firebase so what we can do is just remove that owner completely and now we await on our node service and we just say create new node and then we need an owner user id and remember this owner user id is going to be the actual current user's user id so let's just say final user id is current user dot id okay and then in here we just say user id okay and we're storing that note in here as we were doing before so we didn't change that code at all and then we're seeing new notes also need to be returned so now we need to fix the creation of our new node and that's something that we've already done so that there shouldn't be a separate point really in the caption so we've already done that nothing to take care of right now we also need to take care of now our deleting a notes you remember when we go out out of the node creation view if the node's text was empty we actually delete that node from the database okay right now and now we need to go towards our node service and also delete it by using the new function which is called delete node and let's see what it takes as a parameter it takes a document id and that's our node's document id okay so that's for delete note and now we have another function very useful function that saves the notes and when we go out of the screen if the if that note if the text for that note is not empty very similar to delete node but it kind of does the opposite make sure that the node is present and also that the text to the text editing controller is set if it's not not empty meaning that the text is set then we update the current node so let's then await on it and in here we just say update node those new parameters the document id is going to be our notes document id and the text in here let's see oh we have to just put a comma in there and then we're good to go so that's updating the save node if text not empty function okay now we need to go to our note list view and i'm going to do the same thing in my notes excuse me and let's go ahead and do that do we have any errors in here yes i can see i'm getting an error for update note and i don't really know what the problem actually is let's see document id is required okay and i can see that this is something also we need to update so let's go to your text controller listener function as well and update the note there as well you can see it's doing this so now we now have to say update note and we have a note document id and then we've got text so please ensure that you're you've taken care of the text controller listeners functionality as well um and i'm just making sure that that's exactly what we've done in my notes as well all right so that that was one step back um now let's go and do what the caption at the bottom screen says let's go to our notes list view um notes list view and as you can see at the moment we're working with a list of database notes and we don't want to do this anymore we actually want to work with iterables because that's like the default way that firebase actually works it works with eye troubles it doesn't work with lists so and iterables are actually better because they're like lazy lists so let's change this to an iterable of a cloud node like this and also we change our node callback to be a cloud node if i can spell and also we have to also import this so i'm just going to import cloud node so that error is going to go away i'm going to remove this uh import statement from there now when you're using eye troubles you can't do a subscript like we're doing in here you have to say object element at and then you have your index and that's pretty much what we're doing in here so now if you've made this change in your node callback you made this change from list to iterable and you change this from database node to cloud node and also change this function from a subscript to element add then you shouldn't have any errors in your notes listview.dart file either now we're going to go to a little bit juicier changes that we have to make to ensure that our application works as expected with the cloud storage let's go to notes view notes view like here and you'll see now um actually i can see my notes here uh we have to do a few updates in here because we're not going to work with node service anymore since it doesn't exist but one bigger change that we have to make is as you can see in the cash offset remove the future builder why is that here is the future builder the way it is today you can see the future builders actual future is to get or create a user but do we really need that anymore and the answer is obviously no because previously we were using this feature builder to create a user in our database so that we can associate notes with that user however since now we're going towards firestore and uh cloud storage the users like users in your application are managed by firebase itself so you don't have to create them in that sense when a user has logged in and landed on the main interface of your application that firebase user already exists so you don't have to do anything so we need to remove this future builder so i'm just going to press command dot on it and sometimes visual studio code can actually help with that to remove it but it's not helping at the moment so what i'm going to do in this case as you can see i want to just grab this stream builder in here just grab the stream builder without the return statement okay and find the end of that stream builder visual studio code is helping me very nicely with this line in here and saying this is the end of stream builder so i'm literally just gonna do that and cut it okay so now what you should be ending up with is your future builder like that looks like this and then i'm gonna basically kill that future builder like this okay so then paste your stream builder in the place that your future builder was before so now your body the body of your um of your scaffold should just be the stream builder okay so basically we just got rid of the future builder all right so that was that what we need to do then is to make sure also in here that we're not using that that we're not exposing a user email you see from now on when we create and notes read notes et cetera we're going to use a user id the user's identifier so we're not going to work with our um with the email so i'm also going to go to my note sorry about that so um as the caption at the bottom of the screen indicates let's go and change this to user id and we're just gonna go off service firebase current user and then we're gonna get the id okay so that's our user id and the rest now is kind of history we need to ensure that this view now works with our new node service so let's remove this import from here and now let's say this note service it is a firebase cloud storage so we're going to say firebase cloud storage and in here we just add that and initialize that we say firebase cloud storage which is uh if you remember correctly um it is now a singleton so we're not creating new instances basically by doing this although it looks like we're doing that so inside our stream builder now what we're gonna do is not gonna say all notes anymore like that we're going to say all notes but we're going to pass the owner user id and that owner user id remember we're storing it as a getter call user id and for all our notes in here remember this all notes is going to give us an eye trouble if i move my mouse over there you can see it's an eye trouble of cloud node so it's not a list anymore so let's say i trouble and it's a cloud node in here okay and i can i can see it's complaining that cloud node can't be found so i'm going to import cloud node like that upon deleting in here we also need to make sure that we call the new one that says delete node and in this case we just say node.document id all right so so that is that seems to be working fine but what we got here is a subtype of type firebase cloud storage node service and we're getting that in where are we getting that error let's see if we can find that in here node 2 and that's okay and that's because we probably don't have to do a hot restart and doing a hot restart could kill my scr cpy and i can see that it did that but that's fine too i'm gonna bring up scr cpy like this and i'm gonna do this and i'm gonna run the application now from scratch and this is simply because i mean this is a state management in your application because we had a node service from before and we do a hot hot reload but hot reload all of a sudden says oops this node service that used to be node service is not node service anymore it's a firebase cloud storage so what should i do with it so it's just it's like state residue that is kind of like staying in your application and you can't clean it until you do a hot restart and when i did a hot restart i have a problem with scr cpy so i can't i can't do anything about that problem but let's just run the application from scratch and just make sure everything is working as expected all right now i can see that i've logged into the application and i have no notes all right let me bring up the caption for the next uh topic to talk about so what we need now you can see notes have disappeared and this is a good sign because that kind of means that we have moved away from our crotch storage and now we're not reading those notes that were in the crotch storage anymore so let's go and create some notes so i want to press the plus button in here and i'm just going to say note number one so if i press the back button in here i can see that node number one is appearing here and let's go create another one and let's say note number two great note number one and number two if i press this number two and then change it to note number three you can see that those changes are immediately taking effect okay so let me log out from this user and let's log in with i don't know really which user i was logged in with before i'll log in with this user i can see that user has no notes i'm just going to say van dot's first note go out and then say run dots second note and go out so now if i log out from this one.user in here and if i say i want to log in with another user so like this i can see my note one and three are displayed here so i can just say note number one and two and if i log out from this user and log in again with vanbot i should be able to see van dot's notes through barbaz great so that seems to be working now what we could do i mean if you're just like me and you're curious how this data is actually stored in firebase we could do that so let me open up a window in here and say console and let's go ahead into our project on firebase console and let's go in our database and let's have a look in here as you can see there are four documents two documents per person per user and you can see these two have the same user id and that's the that's the van load user you can see it it starts with a and c and the other two nodes they have another user id which is for pixelity av remember this a and c user what we can do now is actually go in here to the authentication section and have a look at this vendor user and you can see the user ids a and c and the other user actually has erd so if we go back to firestore and look at the two last notes created by pixelity you can see that their user id is erd you can see here all right so very well done congratulations in two chapters we've been able to go away from local uh crud storage to firebase huge feed so well done what we need to do now is i was we as we usually do in other chapters is we're gonna commit our work and also tag it so i'm gonna do some reshuffling on the screen here and grab visual studio code here make the size a little bit bigger kind of ginormous but that's okay and let's have a look at our log and we can see the last step was step 19. let's do a git status and there were a lot of files modified nothing new so i'm just going to say git add all git commit step 20 and push this let's have a look at our logs we have step 19 and step 20 now and if you look at our tags we have up to step 19 up to and including step 19. so let's tag this as step 20 and then push our tags all right that's great as is tradition again at the end of every chapter i talk about what we have to discuss in the chapter that follows and um we've talked quite a lot about now uh allowing the user to store their own notes in the application but it would be a lot more fun if he allowed the user to also share those notes with somebody that they know about somebody that they know like a friend or a family member so that's what we're gonna talk about in the next chapter sharing notes so i'll see you there hello and welcome to chapter 38 of this flutter course in previous chapters we've been talking quite a bit about how we sync our notes with our firestore database and how we can read those notes back and update them it'd be really fun also to be able to share our notes and that's exactly what we're going to take care of in this chapter in order to do that we need to use a plugin called share plus and share plus is a plugin plugin as i've mentioned now so it is not a package where a package extends the existing capabilities of flutter into new heights a plugin takes a completely new route and basically uh goes well beyond beyond what flutter internally can deliver and a packet a plug-in will need to be developed by excuse me a developer or a set of developers and it needs to be written specifically for various platforms that that plugin wants to support for instance ios android so a developer has to go and write some code for ios for android web etc etc in order for that plugin to work on those platforms now here we're going to use the share plus plugin and the share plus plugin is developed by the flutter community so what we're going to have a look at here is to go into pubdev so i'm gonna do that right now excuse me for my throat and in pub dev we're gonna search for uh share plus after you've done that you'll see that you'll end up here and it is by a verified developer called fluttercommunity.dev so you can tap on that and you can get some more information about the developer here and you can see that it supports android ios linux mac os web and windows so what more could you ask for um so it's a free package that you can use in your application and you can see that all you need to do is just to let's go to ins installing and you see you have to say flutter pop add share plus and that's exactly what we're gonna do now in our application so i'm gonna bring our app here and let's go ahead excuse me again in our terminal and i'm gonna rearrange things a little bit here okay actually perhaps i could do the same thing that we've done before so let me increase the size of this terminal so you see it better so let's just do the same thing that was mentioned in the documentation so flutter pub ad share plus so flutter op ad share plus and this share plus since it's it's a whole new plugin that you're adding to your application it's very important that you basically rebuild your application because otherwise it won't be available all right so what you could do is to do a clean and then rebuilds this is cleaning is especially important for ios because sometimes when you add a new plug-in um since flutter uses cocoa pods in order to handle ios dependencies then your build may not actually be able to pick up on that new dependency so it is important to do a clean but for android it's usually not a problem so i'm just gonna excuse me i'm just gonna uh rebuild the application and see if everything is working as expected so i'm gonna stop the application here and i'm just gonna make sure that flutter select device is using my android telephone and then i'm gonna go to main dart and just say run run without debugging and it's it says we have some errors so let's see if we can fix those errors in here okay share plus plugin as you can as i can see we already have the problem now in our application so maybe that's why you have to do a clean so let's go ahead i'm going to go to terminal and i'm going to say flutter clean okay that's going to clean the xcode workspace and hopefully it's going to clean the android as well so i'm just going to say flutter clean android do you mean any of these did i not write clean i wrote clear so clean android oh it's doing the same thing okay so then i'm gonna do flutter and let's just say pop get so that's gonna rebuild all our dependencies so there we go now that those errors have disappeared okay so you may have to have flutter clean and i was trying to get away without using that but i was forced to eventually so in main dart i'm just going to say run without debugging and that's just going to take its time and go to scr cpy and i'm just going to bring scr cpy to the screen as well soon i'll just make sure that i have wi-fi access on this phone because i play quite a lot with wi-fi and hotspots on this android phone so it could be that sometimes i don't actually have wi-fi okay so that seems to be running and here is uh that android phone and i can see that the flutter application is trying to run great able to run this and on that phone so we've done that we've done the clean and rebuild so that's great and the first thing that we're going to take care of is to disallow sharing mt notes you see if if you're on a note screen and you haven't even for instance written anything in your note you shouldn't be able to share that note with anybody because well it's just empty text in there so let's go ahead and we need to take care of that scenario by having a dialogue and we're going to create this dialogue inside this folder excuse me again i've been talking quite a lot today and that's why my throat is giving me some trouble so let's go to lib utilities under dialogues we're going to create this cannot share empty node dialog okay uh let me change the screen layout a little bit here and views we have there and we have services so let's see what we have constant synonyms extension services utilities and views but we don't have so yeah we have utilities and we have dialogue so we have to create a new one let's just say new file and i'm going to say cannot share empty node dialog the dart and you will remember from before that we already have a generic dialogue so what i'm going to do is i'm going to say future of void so the function signature is going to look like this as i'm showing you at the bottom of the screen so let's say show cannot share empty notes dialogue it's quite a long name and then it return it requires a build context so build context context like this okay then what we're going to do in this function is to return our generic dialog and this is something that i'm actually quite proud of that we could create and we are using it so many times now it's unbelievable so we literally have one dialog implementation in the entire application and we're just reusing it and it's truly generic and it's really good so let's in here let's say that we return our generic show generic dialog and it's going to also import that for me it's inside utilities dialog generic dialog so you may have to import that yourself if your editor doesn't allow you to auto import so the context is already there for the title we're just going to say sharing for the content i'm going to say you cannot share an empty note okay and it's options builder remember it's a function that should return um a map and in the map we're just gonna say it has one button that has literally no value so this is going to make it a a dialogue that returns a void or a future of void when we call it here okay so that file is now created now what we're going to do is to go and add that button as you can see it says in create update note view add an icon button to actions of app bar so i'm going to go to my notes as well and create update and let's go ahead and just add that button and there we go i can see that we're using a share icon so i'm going to decrease the size of this of the font is is very big at the moment one more step i i think you can still see the way it is i mean i can see in the video output video it should be visible still even though i've decreased the size so let me go here bring scr cpy i'm gonna close this safari window let's go to create update note view and we already have this button at the at the top i believe let's see do we have any buttons at the top no we actually don't so in our app bar so let's go and create something called actions in here and you can see it's a list of widgets and in here we're just going to say icon button unpressed we're just going to leave it empty and for its icon we're just going to say const icon and and we're going to use icons share remove this parenthesis from there and then put like that okay so now now that we have this icon icon button there if i press on any of these existing notes then we should be able to see a little share button up here at the moment it doesn't do anything because it's on press is empty but we're going to program that program that right now so let's grab the current text of our current node so let's just say that this is equal to our text controller's text and we're going to say if note is not null and the text um actually let's just check for null and the text or actually or this text is empty then we're gonna display our new dialogue that we just implemented so let's just say we await on show cannot what's that function called the show cannot uh we did it inside the cannot share empty notes so i'm just going to copy its name and go in here and paste it and now i'm going to use visual studio code to do the auto importing for me so it needs a build context and in here i'm just going to pass the context and you can see it's complaining that i'm using a weight inside an unpressed function that isn't async so i'm just gonna make this function async okay otherwise what we're gonna do is we're gonna use share and share it is coming from share plus and it can be auto imported okay so i'm gonna just also import that and in here i'm just gonna say share that text it's really just as simple as that so let's go in here and i'm gonna create a new note you can see it has no text i'm going to press the share button and now we see now we're seeing our beautiful little dialogue that says you cannot share an empty note fantastic and if i go out that note is deleted but then if i go to a note that does have text for instance van dot's second note or vandal's first note in in here i'm going to go to van.firstnode and then if i press the share button then i'm going to be presented with in this case android's default share sheet or how you want to call it and on ios you're going to be presented with the default ios sharing activity so this is pretty much it so we didn't have to do much more than this it's literally the call is share.share so you can see it's so simple when you drag in a plug-in especially a plug-in that is from a verified developer especially from flutter community or flutter team or dark dev team themselves all right perfect so that was for sharing there's not much more to sharing than that and we don't have to drag on on this chapter so let's go ahead as this tradition we're gonna go and uh commit our work so i'm gonna do some shuffling around here gonna get rid of scrcpy increase the size of the screen and the font so you see better then let's go to our terminal and i'm gonna have a look at our git's log the previous chapter we committed at step 20 and we also tagged as a step 20. let's just do step 21 in this case so get status we have quite a lot of new stuff so if i say get status in here you can see a new file in here as well so let's commit as step 21 and push our commit and i'm gonna go and tag it and say step 21 as well and then we push our tags as well okay perfect so that's it so if you say git status right now we shouldn't have any uncommitted files very well done so um what we're going to do in the next chapter is very very exciting we're going to delve into a block and if you're a flutter developer from before you'll know what block is maybe or maybe you've heard of it and you want to learn about it so that next chapter is perfect for you if you're not a flutter developer from before you may not know what block is and i'll explain it more however i'll just at the end of the chapter i'm not going to go into the details of the next chapter but what we have to talk about is how at the moment our ui which is our different views are actually working directly with our services so we have some services that for instance can store stuff in the um in the firestore database and we also have some services that are like for our authentication the uis upon pressing the login button we're going to the off service and the off service is coming back with results directly to our ui this is working it's fine however there's better way of doing this and that's through separating the logic of our ui from our business logic ensuring that our ui is doing what is best what it knows best and that's drawing things on the screen but when it comes to handling logic and like making api calls and etc the ui shouldn't really know much about that the ui should just convey its purpose to some sort of a layer that we're going to create in our application with the block library and that that layer will decide okay upon this button being pressed i actually have to do this business logic so i'm very excited actually about the next chapter so grab some refreshments if you want to and i'll see you there hello and welcome to chapter 39 of this flutter course uh in the previous chapter at the end of the previous chapter we talked about that in this chapter we're going to talk about the block library and this is quite a hot topic for flutter developers like if you're a flutter developer and you've just been using vanilla set state in your application you may have already heard about block library and qubits before if you're not a flutter developer from before which i actually think the majority of you taking this course probably have not been fluttered involvers from before so you may have may have not heard about block uh before so i'm just going to start this chapter by explaining what the block library is and why do we need it you see the way that we've created our application at the moment is that we have direct calls from our ui code into our different services in order to interact with data so the ui is very well aware of the business logic so for instance the the create or get existing nodes function that we have when we actually go and create a new node that is already a word of the fact that well if you end up in here i expect a user to be present inside the application so a user should be logged in and that's a sample an example of a ui component being aware of the logic the business logic of our application so they're very they should be very separate from each other otherwise but they're not at the moment so what is block block is a um is a library that we're going to drag into our application soon as you'll also see is a third-party library call i believe it is created by a company called very good ventures vgv and there are various flutter developers and software engineers that are constantly working in order to improve the quality of the block library which is a dependency that will bring into our application and using the block library i mean internally is using streams and streams stream controllers and futures the stuff that's already built into flutter but it's like going to a next level to make things more abstract so that our application isn't directly dependent on its business logic with the ui inter intermixed so the reason we need the block library is just to ensure that our ui is only taking care of the presentation of the ui and it's leaving the rest of the stuff to a business business logic layer excuse me so that's why we need block and we're gonna use it soon in our application excuse me so if that is blocked then what is flutter block you see block in its in its internals is a very simple library that works with streams and stream controllers so it allows you to for instance pass data from here to there and have listeners that listen to changes that are happening in a stream so it's only working with like very low level stream stuff however when you come to your ui layer as you remember i mentioned that block allows you then to separate your business logic from your ui so it's taking care of the business logic using streams and stream controllers and futures but when it comes to the ui part in order to glue this business logic with the ui it needs to be able to work with flutter so the part that works with streams and stream controllers using dart okay and dart asynchronous components but the part that it wants to glue that with your ui needs to come to the flutter world okay and that is that library in itself is called flutter block so fl block is divided into two separate libraries one is block which takes care of the business logic etc and the other one is called flutter block all right but don't worry about it i'll go through these with you one step at a time so you'll learn these excuse me so what we're going to do in this chapter is going to have it literally has nothing to do with our application we've been working with the notes app and in this chapter we're actually going to break our application a little bit by just like literally replacing the home page of our application with a completely new application is nothing scary i i promise you the changes we're going to make is is probably only going to be limited to the main.dark file and what we're going to do is to create a counter application if you if you've worked with flutter before and you've started thinking about maybe moving over to block you may have actually gone to the block library's documentation page and you've seen a counter application in there where you have a plus and a minus button and you can increase and decrease the value that's shown on the screen so that's like the basic counter application but in this example i'm going to show you we're going to take that example to the next level and use the block library and i'm going to introduce all the basics of the block library to you in this chapter but we're gonna take it to the next level and allow the user to enter some value on the screen and that value will then be able to be added or subtracted from the current value that the application stores so it's kind of like a counter application where the user can actually enter the value that needs to be added to the previous account or it needs to be subtracted from the previous account so that's the difference between our simple counter application and what block libraries counter application in its documentation introduces you to all right so let me bring up this caption in here and we're going to talk a little bit about various components of a block and i'm fully aware that pretty much everything i'm saying in this chapter up to where we get to the example is all very much abstract in that it is literally just theory i'm like teaching you theory here i personally am horrible at theory like i didn't excel at school when it came to theory so i'm very aware that a lot of you may also have the same um situation or maybe in the same boat that i am that are not good with theory and that's okay i'll just explain these fast and then we'll go to the implementation so you can put that to practice so for those of you who are interested in the theory of it i'm going to explain different parts of the block library to you now so here the first component of the block library is a class called block now block really it is a container just imagine a class a class that you add events to it and every event that you add to it can produce a state so the way block works is that it it is a class that begins with a state so its output is always a state for instance a state can be logged in a state could be logged out states could be error screen so just imagine different states of the application so that's the input sorry the output the input to it are your events so in your block that will develop you will have inputs that you for instance say log in with this username and password register with this username or this email and password register oh i forgot my password and here's my email so these are events that you produce and give to your block and then in turn your block then looks at its own internals and say oh what was this state before what is the current event then i will produce a new state okay so that's the internal of the block class now when you have a block class when we're gonna subclass from that block class then you will actually need to create an instance of that block class and you will do that using something called a block provider so that's as its name indicates it is a class that creates a um it creates a block instance for you and then it will allow you to do something with that block so i'll see if i actually can show you block provider uh perhaps we could bring up a window in here and i'm just gonna say so block like brarry you cannot see my screen right now but i promise you i will show you soon so here's the uh main page for the block library so i'll increase the font size so you can see it as well so let's go ahead and you can see it's sponsored by very good ventures and stream and medo i'm not sure i i may have butchered this name right now i apologize for that but then if you look at the various parts of block then you'll see let's see if i can find block provider for you here it could be inside the documentation so i'm going to go to get started and then i'm going to have a look at block package block and let's see provider if you can find the provider in here somehow block uh architecture naming convention getting started is there is something uh inside i have a little bit of a problem right now actually finding block provider so let's search for it block provider and then we end up here and i mean this is not the best documentation right now to be honest with you we don't want to look for a blog provider right here but as you can see it says it is a flutter widget which provides a block to its children so this is how you would work with a block provider so it creates the block instance for you and then it will allow you to return a child all right so kind of like a builder but not really all right so that's block provider and as i mentioned you can always go to the block library.dev website in order to get more information about block and read its documentation so the next component you need to know about is block listener so what is a block listener as its name indicates a block listener simply allows you to hook into a um i'll actually see if we have a block listener i can see that we have a blog listener in this application that we're going to develop so you're going to learn about it soon but a block listener as its name indicates it listen to changes to the states of a block that's it so you can do some side effects so displaying a new screen for instance or displaying an error message those are all side effects okay so you can do that with block listener now let's have a look at what a block builder is uses your block state changes to provide you with a widget so as we have a block provider um sorry we talked about block provider before it gives you uh the chance basically to create um a child now inside this child you can then provide a create a block builder that listens for changes inside your block then it allows you to build new widgets based on those changes so it's very much like a future builder or like a stream builder i would say and we've already used stream builder so you should know how they work but again this is just theory so um i'm gonna talk more about these as we actually build our application okay so after all this we also have a block consumer and what a block consumer is that it combine as i've actually written here it combines block listener and block builder so a block consumer listens to changes that happen inside a block and then it will allow you to do both a side effect and it will also allow you to create a widget to display to the user based on those changes all right and again i don't want to go too much into details in uh for a theory because depending on how you learn new things theory may not be your strongest point just like it is not for me so it could be a waste of time for you so let's go ahead and start adding our dependencies in our project so i'm going to bring our notes application to the screen resize it a little bit so we have place for scr cpy as well and we have scr cpy right here as i can see and this is our application okay and the application is running currently so then what we're going to do is going to go ahead and say flutter pop add block and then flutter pop add flutter block so let's go ahead and increase the size in here then i'm going to go to terminal say flutter pop add walk so that's going to do its work and it added one dependency i'm just going to say flutter hub at flutter block all right and this is a package so it's not really a plugin and i don't believe it's a plugin i think it's a package so it could be sufficient for us just to stop our application in here and just say flutter clean that cleans the application that we're going to say fire pub get this could be sufficient so that's gonna do its work and then we're gonna go then we're gonna go to our main dart file and just say run run without debugging and that's gonna just do the greater build if you're running on android or it's gonna use xcode build in order to build your ios application so and i'm just gonna let that do its thing now so let's just wait okay now the build is done and i can see the application running on the screen without a problem so what we need to do as the next step is to do something dramatic and that is to comment out our home page because we're gonna replace our home page with another home page which is gonna use block so it may sound scary but it's not that scary i promise you so let's go into your main dart in here select home page as it stands right there and just comment it out and we're going to create a new stateful widget again and we call it home page so stf and home page the reason this is a stateful widget is because we need a text editing controller as i mentioned how we're going to do this example right now to learn block is to create an application that gives you a text field that you can enter a number into we start with the value of zero in our block so the block holds on to a number and then when you and then we will create two events one an increment event and a decrement event and so when we then give the increment event to our block then we want to grab the current value inside the text field so if we start with zero and then i type five in this text field and i press increment button then i want five to be added to the current state which is 0. so the result will be 5. the next time i will type 10 then press decrement so decrement will be 10 and then it will be 5 minus 10 so we end up with minus -5 so that's the ui that we're going to create and for that we need this home page and the reason it's stateful is because we need to grab that text from our text editing controller okay so so that's our new home page and if i now press command s in here our screen is going to be black because well this this is a home page with no information no scaffold nothing all right so and now let's talk about this absolute beauty that we're going to call counter state you see as i mentioned every block has two very important properties one is its state and the other one is an event an event goes in the block and state is something that comes out the block and so the state as its name indicates describes the state of your block so if you think about it what we expect from our block is a simple integer okay so we could either say our block's output is integer or we could define a state that wraps around that integer so that's exactly what we're gonna do right now so let's go ahead and say we have an abstract class and we call it counter state and then here we have a final integer called value and then we're gonna create an initializer here like that and that's our counter you could also mark this as immutable if you want to all right so let's do that and let me also change the screen layout a little bit here so you see the code better so that's like the basic state of our block okay we're not actually gonna use the state as it is we're gonna create two sub states for this as you will soon see now since we're going to create a text field in the middle kind of like this screen and the user is able then to enter pretty much any text in this text field let's just assume so just normal text not even integer so the user just say hello world and then presses the plus button what should we do in that case plus button plot plus thing like adding hello world to the previous value of five means nothing so we're gonna divide our state into a valid state and an invalid state and then present this to the user in two different ways so let's go ahead and create a class called as i've mentioned there counter stayed valid so i'm going to actually grab that code so we don't have to type it ourselves as you'll soon see here we have a counter state valid extends our counter state which is this one and we have a constant constructor that says okay give me a value a valid value and then i'm going to call my super class with that value all right so that's a valid state now let's then create a an invalid state so let's say class i'm going to bring the correct caption as well invalid state let's say counter state invalid number extends counter state in this case we want this state to actually include some sort of um the value that actually made our state invalid so i'm just going to say that value is a string and we're going to call it invalid value here okay and i'm going to say const and let's just bring a create an initializer here a few required parameters in here and we're just uh like this so in this case we're going to create two required parameters one is the invalid value that caused the error or cause the state of our block to be invalid and the other one is going to be a required of the required parameter of the previous value so because we may actually need the previous value uh or something or maybe like the ui needs to display that to the user so if this is the output of our block the state remember is the output maybe then the ui actually upon me trying to plus hello world with five he may want to use this previous value to populate that text field or populate the ui again and say hello um this value that you entered is invalid but the previous value was this so i'm just going to show that okay so that's why we need previous value and here we're getting an error because we're not calling super let's call super with the previous value okay that's our counter state invalid number okay so we've created our two states that uh come from counter states immutable abstract class okay let's go ahead then and create our counter event and remember counter event is very similar to state so first we actually have to define an event and let's go ahead and define that event like this and you can see it's an abstract class called counter event and it just contains a value so it just says the string that comes from the ui can just go directly into the counter oven that's it and let's make this actually immutable as well and what we're gonna do is to create an event for increment so let's go and say class increment value um or increment event extends counter event okay and in here we're just going to say const create a constant constructor for it and we just grab a value in here so a string value and it should just go to the super that's it and what we need to do is just to grab this event as well and create a decrement event so let's call this decrement here like so and again remember the event is something that we need to trigger and send to the block from the ui all right so we're gonna pack these increment event and decrement event with with the string that the user has entered in the ui and then send it to the block as you'll soon see so let's go ahead now and do the main part of this application which is our block and the way to do that is to create a class if i can spell class and say canner block extends block and you'll see it'll now auto import it for me because we hadn't imported block from before and now let's see if block is imported somewhere here and that's the package block block if your editor doesn't allow you to auto import you will have to do that by hand excuse me so the way to create a block is first you define the state of that block like what type of state does it have sorry events first we start with the counter event and then the counter state okay so if you look at the definition of block class itself you can see the two parameters are or the two generic types are the event and the state so that's here we're saying our events are of type counter event and our states are of type counter state so that's that then let's go ahead and say we have a counter block that's the constructor and what it does is it has to call super you see and our super actually needs the initial states so every block has to have an initial state and that's when you pass your super okay so what we're gonna do is we're going to say we start with the value a valid value of 0. so we say const counter state valid and we start with 0 just like that okay so that's our let's see what happened there seems fine to me yeah okay so that's the initializer in there now what we need to do is actually grab these events as they come remember the ui is gonna uh basically pass us these events so the ui is gonna say here's an increment event with this value here's the decrement event with this value so we need to catch those how do we do that there is a function called on on the block itself that you can use so we're going to say on increment value sorry increment event and then it gives you two parameters so if you look at the function signature of on it actually gives you you see it gives you the event and an emit so let's in here just write event emit and in here we create a new function and put semicolon at the end so that's how we're gonna handle the increment value same we're gonna do for decrement so let's just copy that and paste it in here and just say decrement all right so what are we doing here now remember the event that comes in now is an increment event because we literally said on increment event so we're we're then going to get that integer from our events so remember our increment event actually has is of type counter event and then it has a value of type string so we're gonna try to parse that as an integer okay so we're going to say final integer is int tri parse and we're going to say event dot value like that so and try parse is a function on integer that will try as its name indicates it's gonna try to parse a given string and try to make it an integer and if it can't then that integer is gonna be null so let's say if uh here if integer is not null like that and then we put an else in here and in the case of an else actually so it means that hey you gave us something that we couldn't parse as an integer what do we do with it all right then we're going to use our emit emit is a function on its own you see it's an emitter that allows you then to pass a state out your block so i actually scared myself with my own finger so you you have you got your you got your um this event in now you want to create a state and pass it out that's how you do it with emit all right so we're gonna then say in this case if we got uh if actually let's do integer null if we got null we're going to handle the error here sorry about that so if we got not what we're going to do is we're going to emit a counter state invalid number and we have invalid value and a previous value so the invalid value was this value that was passed to us in here you see event value so let's just say that's the event.value and the next parameter is the previous value and the previous value is always stored inside your state so let me actually do some cleanup in here so you see the code better a comma here so let's see what happened in here you see we're emitting so we're sending a state outside our block so we're saying given an increment event where the integer where the value couldn't be parsed as an integer we're emitting a new state saying that hey your value which was in this event is invalid so that's invalid value and the previous value that we had is stored inside our state so your block in all your on functions you have access to your current state before emitting a new one all right so that's the previous value inside state and if we could actually grab an integer we're going to emit a new value a new state and we're going to say counter state valid okay and we're going to say we take the current value in our state plus it this integer like this right like that so that's for increment and as you'd guess decrement i'm going to remove this comma by the way it was annoying me a little bit and decrement it's very similar to increments so i'm just going to copy this code and remove this decrement one and paste the increment one one more time and then this time i'm just going to change it to decrements like this all right and for the big decrement the only thing you have to do is just to change this plus to a minus and that's it all right wow a lot of work a lot of work so now let's go ahead to our home page in here now we've basically gotten the block down so the block should be working as uh as we want it to so so let's now go into this homepage that we created in here and create our text editing controller so for that i'm just going to say late final text editing controller and we're calling it controller as i can see here let's go into init state and override also the dispose function okay i'm gonna bring the code so you can see it i'm gonna bring it up so in in its state we're gonna instantiate our controller so this is nothing new you've already done this before many times and in here we're gonna dispose of that control uh fantastic all right that part is done so what we need to do now inside our build function we're gonna basically we have to create um our main ui so i'm gonna bring the caption for that as you can see we have to use block provider and block consumer so in the build function right now we only have a container so let's instead of doing a container say okay we want to create a block and we also want to just like make sure everything after this return statement has access to that block so we need the block provider so let's say block provider and block provider is in a flutter block package as you can see here and we haven't imported that yet so let's import that right now in the create parameter we get a context as you'll see i can get visual studio code to complete this for me it says i will give you context and you'll give me a block back so i'll say okay i'll take the context and i'll create a counter block here okay so that's the first parameter then we're getting an error here just because we haven't provided a child here so if i say child in here is a text of hello world and press command s then we see hello world right there okay so in here our task then is to create a scaffold so let's create our scaffold just we usually like we usually do and for our app bar let's create an app bar in here and say app bar title is it const can't see anything because the documentation is all over the place cons text and i'm going to say testing all right so now we have a blog provider that created an instance of our counter block and then we have a scaffold with a beautiful app bar displayed on the screen okay so as the caption at the bottom screen mentions for uh our child the child of our block provider is a scaffold but inside the scaffold itself we have body and for the body then we're going to create a block consumer so remember a block consumer is it is the combination of a block listener and a block builder we need a block consumer here is and the reason for that is upon every pressing of the plus or the minus buttons that we're going to develop soon we want to clear the text inside of our text field so that's a side effect so by us saying that okay whenever there's a new state coming out of our block we want to clear something so this is a signal when you want to do a side effect that has nothing really to do with like a business logic or such then that is your listener so so we're saying that we need a block listener but also we want to for instance be able to have a builder so we want to build our ui based on the current state of the block well that is block builder so if you need a block listener anywhere in your application and a block builder you need to instead use block consumer if you're if you need them at the same level okay so block consumer combines block listener and block builder so that's why we're using block consumer in this block consumer it's going to say okay what block am i operating on so i'm just going to say you're operating on counter block and then it says what state am i operating on and we're going to say counter state let's see if they're available counter and you can i mean i'm not making this up this stuff is present in the documentation if you go to block consumer as well let's see in here what it says it says uh extend state state streamable so that's the the b here b for me means the block and s is the state so it's not so clear because it's working with a lot of generics but you can read the documentation about that okay so let's go in here and in here let's have a look and it's complaining that some named parameters aren't present as you can see named parameter listener is required so let's go ahead and say listener and i'm going to get visual studio code to help me clean this up and upon any new events or sorry upon any new states produced by our blog i want to clear our text editing controller so let's just say text controller uh what do we call it do we call it controller yeah so we're going to say controller clear so we're going to clear the text that is displayed inside the text field soon okay then we need the builder function so in this builder function as you'll see the it will give you the current state and you need to return a widget back okay so what we're going to do in this in this is first we're going to grab like um to see if there's an invalid value so let's just say final invalid value is and we're going to say if this state is a counter state invalid number with a question mark so we're using turner here and we're going to say get the states uh let me bring the code up uh invalid value otherwise we're gonna say empty string so if i then in here say invalid value as you can see it's now a string okay and the reason behind this to be honest with you is so that we can basically display the a little error message to the user should there be an invalid value so if i have if i have entered some information in the text field instead of a number i've entered hello world and then our block produces a counter state invalid number we're going to display an error to user and this error is gonna disappear the next time actually the user enters a valid number in the text field okay so we're gonna use a new widget that we haven't used before called visibility and this visibility is gonna be based on whether there is an invalid state or not so you'll soon see actually how we're gonna implement that so let's go and as our builder's main like return value create a column okay and column has to have children all right so what we're going to do is to first display a text field sorry a text in here so let's just say text and we're going to say current value is equal to this state value all right so that's going to be the current value of our state and if i do command s you can see that it says current value is 0. so that's the current value then what we're going to do is to go ahead and create a visibility widget which in case the current state is counter state invalid number is going to display an error message to the user so let's say we're going to control the visibility of that error message using the visibility widget like this and it's childband is going to be a text that says invalid inputs and then we're going to add the invalid value in here as you can see as we've constructed that up there already and the visibility flag you see we have to return a boolean okay so how do we know that we have to display this widget with visibility and that is if you can grab hold of your state and say okay this state is actually counter state invalid number so let's just say state is counter state invalid number just like that okay so that's how we grab hold of that invisibility and you can see at the moment it's not displayed all right even if we even if we put some um actually let me just say is not and then save it and you'll see now it says invalid input so it's just displayed right there okay but if you say state is then it's going to disappear because the current state is not invalid number okay that was for visibility now let's go and add our text field so where the user can actually enter some information in the ui so let's just say text field as the first parameter we're going to say the controller is our controller okay and what we're going to do is we're going to give it a hint text so let's say decoration is a const inputs decoration like that i'm going to put the code a little bit higher on the screen so for the hint text i'm just going to say enter and number here like this okay and also let's just enforce the keyboard type uh text input type of a number all right but also remember if you oops the controller has not been initialized really i thought we initialized the controller yeah maybe you have to do a hot restart there we go so now we have enter a number here okay great stuff now all right this is what i was going to say even though we have a text field here and we actually said that the keyboard should be numerical but i can still paste non-numerical numbers in here so if i like use the paste functionality in android or is so that's the reason we have that invalid state in case someone else someone actually enters another value except for a number and there are also input formatters in flutter that you can use in order to for instance um avoid users entering non-valid values in your text fields but that's a whole other subject that we're not going to discuss in this chapter so then what we're going to do is we're going to have two text buttons for increment and decrement so let's after this text field create a row so a row is like the opposite of a column whereas a column displays those components vertically one after one after each other a row creates its components horizontally from left to right and left speaking languages and right to left right speaking right side speaking language i believe i think actually row changes it's uh it should at least change is uh how it arranges components based on the language but i'm not quite sure about that so let's say row it has children and it's two text buttons okay that have unpressed at the moment empty and um it's a child it just says cons text just minus like this okay so that's first that's the first button and then for the next one i'm just gonna copy this text button and i'm gonna paste it right here and in here i'm just going to say plus all right so in here when the minus button is tapped i want to convey this information to our block so i want to say grab the controllers text and make sure that you send this increment where is it here increment event to the block so we kind of need to grab hold of our block how do we do that the way to do that is using a convenient function that the good people at good very good ventures have created on context and it's called read and in here you can actually say i want to read my counter block like this okay so this gives you access to your block that has been created by the block provider so let's go ahead and in here let's say after we read that we want to add a new event to it like this and we want to add an increment event that has the value of our controller.txt like this all right so this is how you send events to your block and the same thing since we're actually sorry about that this should be decrement so let's just say decrement like that and we copy the same code and we bring it to our increment function as unpressed button here and instead of decrement then we're going to say increment right perfect okay so let's see now let's test this application so at the moment we have current value zero now if i press the plus button as you can see it says invalid input all right but if i say 2 and press the plus button you can see the value of 2 is entered there if i say hello world here i press minus and it says oh invalid input hello world is invalid and as you can see it clears this text and that's because of this listener here uh this listener because a block consumer is also block listener remember so it's a combination of a block listener and a block uh builder so that's the clear working and the part that is handling this invalid input is this thing so visibility if the current state is an invalid number then this is becoming visible but if the current state is not an invalid number so let's say three four plus two it's going to be three six then the current state is actually not an invalid number is uh the current state should be valid it should be counter state valid so then the visibility is hiding that error message so so that is pretty much it i mean um huge congratulations if you could stick with me throughout this chapter it was very heavy i understand it was a very heavy and very like technical chapter talking a lot about business logic but believe me if you didn't understand like most of the things i talked about you just need to practice i'm no genius nobody who knows how to work with block or stuff like this is a genius everybody has practice put it into practice done their own applications done this test just go and create this counter application that i just created try not to look at the code that i've written or rewritten in this just try to remember the stuff from your memory and after exercise and practice and practice and practice and you will get it and you will get the idea of what a state is you'll get the idea of what events are what block is and read documentations and you'll get this eventually i promise you that as is tradition we're gonna now uh since we're done with what we prom promised in this chapter we're gonna go and commit our code so let me change the screen layout a little bit and go to uh terminal and increase the size get rid of the crcpy and let's have a look at our log last chapter we committed step 21 so let's see git status and there were just a few things changed so let's add everything and just say git commit step 22 and let's push our chase and then i'm just going to say git commits sorry it's a tag to see our last tag and i can see it was 21. so let's tag this as step 22 and say git push tags there we go so now step 22 is also tagged and ready so what is to come this is also a tradition we have at the end of every chapter we'll talk about what we're what we need to discuss in the next chapter and what we need to discuss in the next chapter is and we will convert our auth process to using block so we've now talked we've act we actually got our auth logic inside our application and that was our auth service i don't know if you remember from before but we need to convert this auth service to block and uh so in that way we're actually putting our knowledge about block into use and combining it with what we've already developed to make our application better and our logic not so spread around everywhere in the ui so if you want grab some refreshments tea or coffee and i'll see you in the next chapter hello everyone and welcome to chapter 40 of this letter course in previous chapters we've been talking about um our aus process and also storing um users notes into a firestore database and in the previous chapter we also talked about block so um i'm very aware that block could be an intimidating um topic for some developers and that getting started with block could just be conceived as like an extra step that you think you don't need however i can assure you when you get more into professional software development and which is which may not be your goal i completely am aware of that but when you get more and more to professional software development you'll understand that you need to separate various layers of your product and that the um the presentation layer where you're taking care of for instance displaying stuff on the on the screen to the user shouldn't really have to talk with your authentication directly um or for instance your authentication layer doesn't necessarily have to depend at all on other parts of the application so block is gonna allow you to in a very clean and concise way to separate the various uh layers of your application into their own concern layers so and the services are going to be only concerned with services and then your ui is going to be only concerned with ui and so on so and so forth so um it could be beneficial if you could actually before starting with this chapter to go to the previous chapter and maybe watch it again or maybe even practice yourself with block um i understand i know for sure that the block libraries website as we looked at in the previous chapter they have quite a lot of examples and i highly suggest that you go through some of those examples at least and develop and implement those examples also yourself to get a bet to get a better hang of what a block actually means and how you're supposed to use it so if you've taken care of that and you understand like the basics of block then we're we're we should be good to go for this chapter so let me bring up the caption for what we're actually going to do in this chapter you see the way we have our application at the moment is that we have our authentication service and our authentication service let me just bring that to the screen here and let's have a quick look at it so if i go to our auth service you'll see that we have quite a few function functions in here we have create user and we have uh we are exposing the current user we have login logouts and email verification and initialize now this is all good however we are it's very raw the way it is in that the ui is literally making calls to our auth service which in case which in turn is making calls to a provider which is our for instance um firebase provider author provider so if you go in here you'll see firebase auth provider and that is talking directly with firebase so in a way you could say that the ui is talking pretty much directly with firebase it's just going through some functions to get to firebase but that's what pretty much it's doing so what we want to do in this chapter is to try to make sure that our authentication is behind a layer of block meaning that all the logic that has anything to do with authentication is hidden behind a layer which we're going to call off block so that's going to be our off block so it's like the and as you remember from the previous chapter every block has two parameters one is what is what comes inside the block so what's entered and what is the output the input to your block are your events so you pass for instance your ui upon pressing a button then you you pass an event a packaged event that we call our auth event you're gonna pack package that up with any parameters that that particular event is required it is required from you you take that event and you give it to your auth lock then your off block is then gonna have some time to process you remember we have these on function functions on your uh off on your blocks when we talked about the counter block we had on increment event on the command event etc so these are the events that come in so we're going to package those events up from our ui and pass them to our off block then our off block is going to have some time for itself to process those events and based on those events that it has it has received and based on its current state it's gonna either output the same state or it's gonna output a new state so events come in and states go out and the off block sits in the middle so event off block and estate and these are three components that we're going to develop in this chapter so let's go ahead and take care of our state and remember again state as its name indicates is the state of authentication either you're logged in or you're logged out okay and you could also be logged out with an error remember so you're either logged in or logged out with an error so we're going to start looking at these off states so what we need to first do is to create a file as the caption indicates under lip services auth block off state so let me do some reshuffling on the screen here maybe decrease the font size a little bit because it's just ginormous the way it is right now so maybe this font is a little bit better i'm going to put visual studio studio code in there to the left and then i'm gonna bring scr cpy to the right okay so i'm gonna close all these tabs that i have right here how we left the application in the previous chapter and let's go ahead inside lib let's let's see actually what we have in here we have lib and we have services and under services we already have auth but we don't have a folder called block at the moment we have auth provider etc etc so let's go in off and just create a new file in here and say block slash auth state state like this dot dart okay so that's our off state now if you remember from the previous chapter when we talked about the counter block um usually states are immutable and that they're also they're like at the generic states that every other state in your block inherits from is usually an abstract immutable class meaning that it is a class pretty much almost with no logic at all it may have a constant constructor but in and on itself it does nothing so it just is dictating that hey every state that comes out of this off block is of this type okay so let's go ahead and create our off state so maybe i should actually increase the size of that font so we're going to start by writing um our states as you can see so we're going to code that in auth state.dart file so i'm going to go ahead and just say abstract class auth state okay and let's just create a constant constructor for it as well in case one of our states needs to also have a constant constructor so this is this is a pattern that you may have already been used to by creating abstract classes and if you have like sub classes that conform to your abstract classes and those subclasses actually want to have constant constructors then you need to have a constant constructor in your abstract class as well so that those subclasses can actually call that const constructor in the abstract class otherwise you won't be able to have constant constructors for your subclasses so for instance if i say abstract class blah extends off state and if i say const blah like this you can see it says a constant constructor can't call a non-constant superconstructor and that is the reason that i usually create a cons constructor for my um classes for states and for um the events okay okay now we have our abstract class off state now let's go and make it immutable and for that we need to import material or actually it is foundation let's import from foundation in that case and we could just say show immutable can we do it like that yeah that works as well okay so that's that we have a generic off state so um actually i don't mean generic in terms of like a dart generics which i just mean an abstract class that every other off state can conform to okay so we have basically a low i mean we have quite a few states so i'm just going to start doing and doing and creating those off states one at a time so while you're authenticating for instance while you're let's say that you are you've just opened the application and then we need to basically tell our authentication um provider which is firebase to initialize itself while it's doing that then our auth state is in the state of loading or initializing whatever you want to call it but we kind of need have to have a state that indicates to the application that hey something is happening with the auth process and it is in the in the process of loading so let's go ahead and define that so let's just say off state loading extends off state just like that okay and this could also have a const constructor so let's just say like that okay so that's the state of loading and we can actually use the state of loading and i believe we're actually going to use it while the user for instance is has just opened the application and the applications is initializing and we can also use it for instance when you tap the login button in order to log into the application and we're communicating with firebase and that is also a state of loading okay so you will see soon now these states are very important how the ui then reacts to various events that are or various states that are happening in our off block so let's say that we have the loading state let's just define a a logged in state so when the user has already logged into our application then that is its own separate state so let's go ahead and say off state logged in and it extends the off state and now this is important to see okay when you're logged into the application what does the application actually need from us well the only thing the application needs from us when you have logged in with the user is the current user at the moment we are going to our auth provider and or our auth service and grabbing the current user but if we're gonna move over to block and like blockifying our entire auth process then it makes more sense for us to grab the current user that has logged into the application from the current state of our auth block it's it's i mean to me it's really beautiful because it makes sure that we can separate the auth service and the auth provider from the ui by putting a block in the middle so i mean the name kind of it may sound like you're blocking the ui but that's not how block is written as bloc it's not block so but that's that's what we need to do so let's just say we have the final off user and it's going to auto import it for me if you're using vim if you're on linux and or if you're using subline that it's not able to auto import things then you'll need to auto you need to import off user yourself okay so let's say that a state of logged in or always carries with itself the currently logged in user okay so we're just going to say user and i'm going to create a constant constructor then for this class as well which in turn is going to cause automatically for us on off state okay so that's our state of logged in now let's say that we're going to define also a logged out state and but also we want to um we actually before we go to log out maybe we have to talk about talk about login when you're trying to log in a user in our application today if we go to our login view you'll see that upon pressing the button to log in then we're doing a try a weight of auth service firebase login so we're literally going towards firebase directly and then if anything goes wrong then we're doing like a user not found off exception wrong password off exception so we're handling our exceptions in this way and the way that we need to do this now with uh fire with block is that we need to produce a state you see the ui needs to only talk with that block so it says hey block here's an event go log in and then it says and then a blog is going to do some processing and then maybe it says oh incorrect user incorrect email or password is wrong or whatever so that needs to be its own state so at the point where an exception has occurred during login that is a state login failure we're going to call it login failure so the ui is then going to react to that particular state in order to display for instance an error message to the user like we are doing today so let's go ahead and say class off state log in failure and we're going to extend our off state in here and what we're going to do is that upon a login failure we need to carry with that state the actual exception that caused the failure so let's just in here say exception exception just like we're doing we're carrying the user with us when you log in we carry the exception with us as well if you couldn't log in okay so that's how you should think as well so your state should carry with them all the information the ui or the consumer of that blog requires in order to be able to fulfill its requirements so in this case upon not being able to log in the ui is going to require the actual exception that occurred so that it can switch on it or do some if statements and see what kind of exception it was and display the correct correct message to the user so let's go ahead and then define that and since we've expected an exception in here i'm going to create a constant constructor here as well like that oh actually we got a warning here it says prefer declaring cons constructors on immutable classes that's actually beautiful yes sorry constant fantastic okay so that's our login failure then what we need is you remember also i mean at the moment since we have our counter block uh in here and the counter application that we did in the previous chapter i can't show you the ui of the application but if you can recall what we also had is if you try to log in with a user and that user's email is not verified when they were actually gonna what we are what we were doing is that we were sending the the user to the needs verification view or something that we call it let's say let's see very verify email view right so we sent the user to this view and we need to also we need to also produce that state so upon user pressing the login button and if our off block realizes that hey this user does exist but here she hasn't verified their email address then we're gonna produce a state telling you ui that hey this user needs to verify their information so let's go ahead and implement that so we're going to say class auth state needs verification extends off state okay and then here we're just gonna grab this as a cons constructor like this all right so that's that and also after doing that so now we have login and login failure we have needs verification and we have the loading state if we're in the middle of for instance making an api call that could take some time the other state that we need is also logged out if you're in the log out state then we need to produce that so let's just say class off state um why is everything yellow class state logged out okay and this is going to extend offset as well let's then make a constant constructor for this like this great all right so log out when you're logged out you're logged out there's nothing that the logged out state actually has to carry with itself it doesn't have to carry the currently logged in user or anything or even the current user in firebase even if even if you have anonymous users the logged out state for our application doesn't have to carry with itself anything okay and last but not least we also have to define our logout errors and so upon logging out you could also encounter some errors like if if a firebase for some reason is trying to make an api call and that api call doesn't succeed then it is going to give us an error so let's just define that as well let's just say class you see we have that already for login failure let's go and actually copy that and paste it here and here instead of login i'm just going to say log out failure and copy that name and put it in the consonant constructor as well great so we have one two three four five and six um off states so that looks actually really good so our auth states are now defined okay and please save this file as well now we need to define the inputs you see the states have been the output of our off block which we're going to write soon the off block we haven't written it yet but these have been the outputs now what are the inputs imagine in our off inputs we have to think about what the ui what the ui is actually going to call so the ui is going to send packages of data to this off block and these packages of data are the events so we need to make sure that the events can contain with them the data that the ui can package and send to our off block for instance during logging in what event is it okay it's let's just say off event login what should it contain well it should be the email and password something like that okay upon log out okay that's a log out event what should it contain no it's nothing it's just a log out event it shouldn't even provide the email and password it should log out the currently logged in user from the application so we need to think about events and their consumers and also the states and their consumers so you have to pack enough information both into your states and into your events so that the consumer of your blog can actually both receive enough information and be able to pack enough information to send to your auth let's start to your block okay now what we need to do is just go and define our auth event right here in lib services auth block off state we have written our off state so i'm just going to close that file and let's go in the same folder called blocking here you see lib services auth block we're going to create a new file called auth event so right click new file off event and marked all right and now we have our off event and we need to do something very similar to what we did with off state in that we need to define a um a super class an abstract class that basically engulfs all other um auth event so every auth event in our application is going to be of this type so let's say immutable and we don't have access to it yet so let's just um let me just write it for now let's just abstract class of events and a constant constructor which you now know why we're creating an immutable comes from foundation we've already done this so import immutable okay uh oh use show sorry i programming quite a lot of languages python and rust and swift and you name it javascript so it's sometimes a little bit messy in my head about imports so um there are quite a lot of different ways of important things in different languages so i sometimes mix them up and so now we have our aus event which is an immutable abstract class so now what we need from the ui is upon it wanting to initialize our auth you see at the moment let's see actually what we have in our main dart file this is just us having a look and you can see here and that's that's the counter block but how we had it before is if you remember in our home page we had upon the entire home page being loaded we were saying auth service firebase initialize so this is a signal from the ui that needs to now go to our auth block and say hey initialize yourself so let's define that signal or event let's say auth event initialize extends off event [Music] and it has no parameters it's as you saw in main darts it's literally just a function being called so we're going to represent it with an event that has no parameters but it has a constant okay that's that's that okay we have now our auth event initialize what we also need is an auth event for logging in and as i mentioned it's very simple it's just with an email and password so let's just go ahead and say off of event login something like this or log in with a capital i extends off event and we need we need two parameters to be passed in here let's just say final string email and we also need a password so let's just type that here password and now we have the email and password we're just going to create a constructor here and make it constant just like that okay so now we have our login event and so login event should carry with itself every piece of information that the auth block will need in the future in order to log in that user into the into our provider which in this case is firebase okay so after defining login we also need to define log out now if you have a look at our um there are so many files in here so views and we have notes and then we have excuse me we have notes view if you have a look at notes view if you have a look at this and log out what it's doing as you can see it's a weight of service firebase log out so so this is a clear event with no parameters it's just telling the off block then or in this case the off service that hey you need to log out no parameters log out the current user okay so let's go and define that as well in here so let's just say class of event log out extends off event and it has no parameters as i mentioned so let's create a constant constructor for it which in turn is going to call the constant constructor of the abstract class called auth event all right fantastic those were the only events that we had to define initialize login and log out so these are the inputs to the block and then we had our auth states which are the output our outputs of our off block which we're gonna write uh right now actually so we have the events and the states the only thing that's missing is the uh auth block itself so let's go ahead inside this block folder create an off block file so off block oops block um dart so now we need to actually write our auth block and this is for me at least this is like the most uh this is the most fun um so because we're going to put together three pieces of uh two pieces of information the states and the events and now we're creating the actual login the logic of our authentication block so this is very exciting so let's say class off block like this extend block now it's going to complain saying that well it doesn't exist yet so let's go ahead and import that import that as you can see here now remember block if you go into source code it has two parameters there's two generic data types in here event and state our events are called off event and it's going to auto import that and then we have to say auth state like this which also is going to be auto imported so just like our off service if we go back to our off service in here you'll see that our auth service at the moment is taking in as a parameter a provider so we're going to do the exact same thing in our auth block it's going to say give us a provider to work with is it a firebase provider or what is it so but we're not gonna directly go and say give us a firebase provider we're gonna say give us an auth provider remember that we had an abstract class called auth provider here which pretty much defines the uh the logic or defines the interface for every auth provider whether it's a firebase auth provider gmail auto provider facebook whatever that's how the interface should look like okay so what we need to do is to create a um a constructor and in here what we're going to say is to give us an auth provider so we expect an auth provider auto import okay so if you're getting errors here it's because you have an imported off provider the way visual studio code just imported it for me right now and let's say that we get that we call the provider in our constructor and if you remember correctly from the previous chapter we need to also make sure that auth block always has an initial initial state so that's what block as a super class requires so let's see you see that's the constructor of the block libraries block class that says it should have an initial state so our initial initial state is going to be in the k in the state of loading so let's say off state loading like that and we create a constant okay so and i can see right now that i'm not using scr cpy so much so i'm just gonna minimize or yeah i'm just moving it to another screen so we don't get bothered by it and that enables me then to increase the size of visual studio code in width so it's a little bit easier to read so i'm gonna go create a constant here and then we're gonna create our curly brackets in order to go to the actual initializer or the constructor of this auth block okay all right now your job in here inside the auth block is to actually handle various events and then based on those events produce a state what is the first event remember this event initialize so if the user tells us to initialize our uh auth block what should we do well we should go to that provider and actually tell it to initialize okay so let's go ahead and do that so i'm just going to say on off event initialize and remember every on function you see it takes the the event let's see actually yeah it's the event and then an emitter it's not so clear from this i mean from looking at this it's quite generic it's i would say it's too generic but uh but that's that's the way it is so we take the event that came in so in case you need to extract some data from your initialize in this case initialize is an empty class so it has no data but it when we actually start loading for instance and we start handling the login event we do need the events to actually come in so that we can extract this email and password okay but in the case of event initialize the event is pretty much useless so we could literally ignore it by just doing something like this okay but we're gonna take it in anyways so now that we have that event we the second parameter in here is called emit and emits then allows you to um actually emit and send states from your off block out to whoever is watching the stage changes in your off block which is going to be our ui okay so emit is your way out is your communication channel to the outside world so let's make this function asynchronous because we are actually gonna call our provider and call some asynchronous functionality on it so let's go ahead and see if we can do that so the first thing that we need to do in here is to call our provider and say initialize okay and initialize you can see is it returns a future of void so i'm just gonna wait on it all right so then what we're gonna do is to say okay after doing that we're gonna say final user is provider current user and that is an optional off user if you remember from its function signal or from its getter signature you see now if the auth user is null after doing an initialize then we know that the state should be logged out it means we initialize the provider but there is no user you are logged out okay so let's just say if user is null then we're going to emit a new state and we're going to say auth state logged out like this as a constant okay however if there is a user so so now we have a user we're sure that we're not coming into this block here that says auth user is null if there is a user but that user is not email verified then we're going to produce another state so let's say if else if uh user is email verified not so it's not email verified then we're gonna emit um a const off state uh needs verification okay so that makes sense as well otherwise we're going to say where our state is bought state logged in and remember the logged in state actually needs your user okay so um that is actually working quite well right now and now it says user that shouldn't really happen because the user actually isn't null so we have already checked the user so we could put let's see what is it actually complaining about user value of type null can't be assigned to a parameter of auth user in a cons constructor try using a subtype or removing the keyword const and i mean i understand this part to be honest with you and that's correct that's a mistake that i've made in here and that's because i said a constant constructor is being called with a user which is a variable so you should also know that we can't do that all right because user in itself is not const hence we can't call a const constructor on a on a state that uses a variable user okay great now we've handled the initialize events all right what we need to do is to handle the login event so let's go ahead after this i'm just going to put a comment in here and just say initialize just to make things a little bit separate from each other and then log in i'm going to bring the code up so you see it sorry about that it was a little bit hidden when i wrote this comment so now you can see how it looks like then we're going to handle login events so remember again an event is something that the ui is going to send us and that event if you remember it has a username sorry an email and a password then we're going to unpack that email and password provided to give it to our provider and provide it to our provider give it to the provider and then react to the various results that come back from the provider okay so so we're gonna say then on off event login oops yeah login and we're going to say event and then emit and we're going to say this is an async function and it goes in here all right so okay now this is the beauty of a blog using emit you can let your consumers know what you're up to let's say someone says login what is the first thing that we're up to yeah we are loading we are in the state of loading because we are going to start loading and make api calls and that's exactly why we have these off states in here remember we have the auth state of loading so let's change our state as soon as you tell us to log in we're going to say oh now we're loading okay because we don't have a state that says logging in but we have a general state that says loading if you want to you could remove this loading state and just say i have a class for instance auth state logging in that's also acceptable but then you have to have a um something something in uh state for everything like even if you're logging out you should say off state uh logging out uh so then you have to have a loading state for pretty much all the states that do something asynchronous and that's why we haven't done that we have a generic or a general loading state that indicates to the outside world that hey you are doing something okay don't worry about all these saved operations that have been in this off state file i pretty much i mean i didn't change anything in this file okay so it is how we left it when we finished off stage all right so let's in here then emit a an auth state loading just like that and upon logging in what we need to do is just to grab the email so we're just going to say email is equal to the event email and password is equal to the event password okay and then we're gonna do a try and catch like this and tell our provider so we're gonna say await provider um i believe we have let's see what the problem in here avoid okay that's fine let's then create a user so let's say final user is equal to provider dot we have a login function on our provider excuse me and here we're literally passing email and password to that function okay and remember login function at the provider level it could throw an exception but that's fine because we have a catch in here so if we go to the login function in our auth provider let's see if we can find firebase auth provider inside the login function let's see if we can find out here we have various exceptions that are going to be thrown user not found wrong password generic auth exception so if any of those exceptions happen we're going to come into this catch block all right so now that we have a user if nothing happens if no exceptions happen then we're going to emit and we're going to say const or actually we can't do a const because a user is a variable so we're going to say auth state logged in and it's just going to say give us a user and that's the user should any exception happen we're going to emit a login failure and we're going to say emit auth state oops log what's it failure login failure i can see yeah and in here we literally pass the exception there can't be assigned and then so we probably just have to see i can i mean i understand this exception as well it's because exceptions in dart maybe this is a little bit of a side talk but exceptions in dart can be anything i mean i posted something on linkedin on twitter a while ago saying that well you can even throw an enum value as an exception and that's why in dart exceptions are of type object and in this case i believe they're even object optional object no it's actually an object so here the error is that you're saying that off state login failure that needs an exception but you're passing it an object so let's say on exception if an exception happens then uh and that's because we know that our login function is not act let's have a look at the login function and see if it can throw anything other than an exception and we see now that it has a general catch block which throws a generic auth exception which in turn is an exception so in our application right now as it is we're not throwing anything that is not an exception so every exception is coming from the exception class all right fantastic now we have our login um event in place and we're emitting the correct states logged in or login failure now we have to handle log out so let me bring the code up and we're going to say log out and this is very similar to login a little bit less code so let's just say on again we're going to handle inputs okay so off event log out so if someone tells us to log out like this then we're gonna say okay we take the state oh so much documentation everywhere um sorry the event and then the emit and then we make this function asynchronous like that and the first thing that we have to do again since in log out we're going to call the logout on our provider which is an asynchronous function we need to tell the ui about that we need to tell the ui that upon you requesting log out from the off block you have to do some loading what better way of indicating that to the output to the outside world by actually changing our state using emit so we're going to say off state loading okay so that's us indicating to the outside world that we're doing something all right so uh let's then do a try and catch in here cat on exception catch e like this if an exception occurs then we're going to say emit off states failure we had a log out failure and that expected an exception so i'm just going to put the e in there we could also put this image in try it doesn't matter because this doesn't really throw an exception it can never throw an exception but we're going to put it in try catch because i believe just it's a little bit cleaner it's it's like a transaction so what we're gonna do is to say await our provider and log out in here all right and should the logout actually go through then we're going to go to the next line which is line 40 for me maybe another line number for you and then in this case we're just going to emit a const of off state log out fantastic all right so that was it really i mean it was just a lot of talk a lot of creation of like uh classes but um we've now gotten there so now we have an off block and then we have our auth event and off state so now that we have those i'm going to close those tabs after you've saved them so make sure that those files are also saved then what we're going to do is just to get rid of that ugly counter block that we created in the previous chapter which kind of is like dirtying down our main user interface so let's go to main dart and let's grab this home page the way we have here let's see so let's go in this new home page that we created for our counter block and just completely remove that everything that is related to that counter block okay and then let's go ahead and bring back our normal home page like that right fantastic uh we have flutter block and block in there and that is causing a little a little bit of a problem but that's okay too so what we need to do now is to actually go and let me bring up the next captioning here as you can see now we need to use block provider and block builder and we're going to do that in our main dart file so i hope you haven't jumped over the previous chapter because i talked a lot about in the previous chapter about block providers block builders block listeners block consumers and what they are how they're different from each other and there's a lot of information and material available online that you can read also about all these things online but if you've skimmed over that chapter and didn't understand really how things worked what we need in here just think of it that our main application needs to offlock the auth block is responsible now from this point on to handle everything related to authentication it is not the ui part remember the ui part is completely separate that's the goal of block in its core to separate business logic from presentation logic so your presentation logic everything related to the ui for instance displaying dialogues displaying exceptions handling etc etc etc that's all in the ui has nothing to do with all of what but the off block is going to be responsible for actually initializing the authentication process and also with with firebase and also allowing us to log in and log out et cetera we need the auth block so how do we get off block in our main application since the entire application is dependent on the auth block even when you're in the main ui of the application you should still be able to for instance log out then we could literally say that oh everything inside our application in the main function is gonna be dependent on that off block so what we're gonna do is in our home page let's see in here here we're right now saying we have a home const homepage you see actually let me command s this and bring uh scrcpy bag back here so now we see our notes back so home page is fixed now so what we are going to do in here we're going to instead of a const homepage we're going to replace this with an auth provider okay now we could do this as you can see we have um do we have sorry with a block provider i have the block extension in visual studio code which then gives me the ability to wrap things with various block components and flutter block components and you can go to extensions and install the block libraries extension for visual studio code if you're if you're using another uh development environment if you're for instance using sublime you may not have that ability so what you'll need to do is to write this by hand so i'm gonna take advantage of wrapping this homepage with a block provider meaning that my home page now let's see here let's say this is a const as well is a home page before its creation is dependent on the creation of a block okay so let's go in here and say the block provider is also using our off block which i believe now visual studio code is going to auto import you may need to import that by hand if you are not using visual studio code or an or text editor or an id that has this feature now in the create parameter of our block provider we actually have to create the uh block that we promised we're going to create and you can see that being created here so and i can now see directly in here it's creating a const provider but we can't have that simply because our auth block if we go back to our off block in here i believe that our constructor is not a constant so if you put const in there you can see that it's not allowing us to do that simply because block itself as a library as a class here it has no constant constructor so we can't have a constant provider so let's remove that const from there okay now in here we have to say it should create offlock and if you remember offblock requires an auth provider so let's go in here and say firebase off fire and that's going to be auto imported as well perfect now we have our block provider that's fantastic so now what we need to do is to have a look in here and see what else we have to change in our main functionality well what we have at the moment i mean we have of course we have this functionality here to create the auth block for us in the main function but we're not actually really using that in inside here we're using future builder okay so what we need to do is instead of using future builder let's use our um what we're going to do is we're going to use block provider i'm sorry block builder and block builder is kind of like future builder but it's going to use but it's going to use our block which is defined here now this may seem all very complicated to begin with and what you need to understand is that there is a lot of magic happening behind the scenes in block in that when you create a block provider in here and then it gets a context and then it goes here to create the block what's happening internally in block is that that context itself is gonna get injected with your off block so when you create the auth login here this context from this point on inside the entire application is going to be it's going to be populated with an auth block that you can read from okay and i'll show you now how so in the build function of your homepage what you need to do in here we're going to say see we have this future we have the switch of the snapshot and that's all fine so let's just then go ahead actually what we need to do to be honest with you is to um we're not going to use so much of this code so it's perhaps makes more sense just to shift it down a little bit to make room for our block provider okay so in uh sorry a block builder so our block builder has a builder function but we also are going to get hold off our um actual block in here in the block builder as you'll soon see when you come to your home page what the first thing that we need to do is to tell our os block to initialize itself do you remember our auth block has this um event handling for initialize so somehow in this build function we need to tell our author like hey initialize yourself so how do we get hold of that i talked about this how do we hold off how do we get hold of the off block in here since we don't have access to it here but i just mentioned that when you create an auth provider sorry a blog provider that blog provider is going to inject your off block into the context so the the auth block is hidden somewhere in this context and the way to read that is you just say context dot read and then there's a you see there's a function in here and if you go into this read function you see it actually comes from a provider here so flutter provider provider dart okay so in context read let's just say that we're looking for auth walk and what we're going to tell it to is to tell it to initialize but if you put dot in here you see there is no function called initialize or anything and that's because the way you communicate with an auth block as we saw in um or the way that you communicate with a block generally is that you send it messages using its add function so add is your way of communicating with your block or your blocks about various events that you're sending okay so in this in here we're going to say add and then we're going to say auth event okay if you're getting an error about this auth event initialize not being in context it's probably because you don't have an auto import for this uh file in here which i had so we have now we are sending initialize events um to our auth block now that that is done we need to do our block builder so in this builder function let me go here and get help from visual studio code to complete that and you can see now i get a context and a state so so let's go ahead and handle various states that could happen during this period during the initialization period okay so let's say if the state is off state logged in so if we are actually logged in then we're gonna return const notes view like that so that is this view all right else if state is auth state needs verification then let's see what we were doing we were returning this verify email view so let's go ahead and do that here as well now if excuse me if the state is logged out excuse me again it's off it's logged out then let's see how we were handling that before um if we were logged out we were going to the login view like like here so if we were logged out then we should send the user to the login view otherwise if it's not those states so what can we do let's say that in the future you're going to add some more states that this block block builder right now is not able to handle so um what you want is still an application that is in working condition you shouldn't crash or anything so let's just in this case return a scaffold and make it constant and let's in the body of our scaffold create a circular progress indicator just like that all right so it looks like that also you could mark your block builder as well to say that it has the off block and also it has off states you remember block builder has these parameters in you see the builder and sorry the block itself and the state that's why i've marked them like this okay and now as you can see state is not an uh it's not just a normal object anymore it's an off state before writing that state was just an object but now i've marked it as off state and you can see it's become an off state here as well great stuff now let's get rid of the future builder that we have from before so i'm going to remove all that code excuse me and now you can see we have our off our block builder here and a block provider up there so that's all we have to do um now it's great actually we're getting this issue um and you can see it's i love these errors i mean a lot of developers are scared of stuff like this but it's so important to actually read what's inside this what is what it's telling us is this happens because you use the build context that does not include the provider of your choice and that's because of this you see is this thing context read auth block so so what flutter is saying that hey you're expecting me to extract an off block from the context but it's not there okay why is it not there it's simply because the main function i've mentioned this quite a few times in the course but i believe it's so important that i want to mention it again the main function does not get called during hot reloads and i just did a hot reload by doing command s so there is no block inside the context because the block is actually created by the block provider which is inside the main function so if i want this auth block to be injected in the build context then i have to do a hot restart so now the application is working as it should all right excuse me so we've now taken care of our main dart file removed the stuff that we have for the counter application which we created with auth with which we created with block and now we've moved to using our first two components from block which is block provider and also block builder we have a few unused imports so let's just remove those okay just to make sure that this file is quite clean the part is that it's done now what we need to do is to use as you can see in the caption we need to use our off block in the login view and the only thing we really need to do is upon pressing the login button we need to send the off event login to our auth block that's very very simple so let's go ahead and take care of that this is just easy from go to login view as the caption indicates and where we're calling this login functionality here as you can see we're saying um we're taking the email and password and we're just yeah calling a login so let's see we also have is email verified so we're not gonna take care of that at this point so we're not gonna really uh take care of email verified so in this in this try statement here verify email route we will fix that soon so let's just remove this try everything in the try block and what we need to do in here we need to read our block our auth block and then convey an event to it okay how do we read the the a block and that is using context dot read or what was it called read i believe actually yeah but remember autoblock and three function is not available until you import your provider and i can see in here says package provider src but in the in our main file we didn't actually import provider so we've imported our flutter block so let's go ahead and do that as well in here so inside login view dart please import your flutter block so now all of a sudden we're going to have access to the read function okay so in there what we what we're going to do is just to add an event to our let's see if we can get access oh for that we need probably to import block as well so package excuse me block and then okay let's see if then all of a sudden we're gonna get the add functionality in here context read oh sorry about that it's because this is a function i need to call the function so add and i may then get away by removing block from here i apologize for that we didn't really need to import um block library as such okay i understand this is a little bit jumpy that's okay though so all we're doing is that we removed everything in the try uh block and we're removing we're replacing that using context read we're reading our off block from the build context and now we want to tell it to log in so you remember we had a l off event login so let's go ahead and do that and as you can see it's going to auto import it for us so i mean here we have the email and password fantastic so that's that all right so that's gonna send that event and then we have the rest of the exemptions now remember i understand you may think oh exceptions though how are we handling them well we are not at the moment our exception handling is completely broken by going towards using auth block everything is broken as far as exceptions go because um you can see the way our auth block actually throws exceptions is by emitting them inside states so you see it says a state login failure and then there's an exception in it so we're not handling those at the moment so you're right exceptions are completely broken for the entirety of this chapter and that's okay because we're gonna fix them exactly right after this chapter so now you know what's coming in the next chapter as well all right that's that's for uh our login so i don't think we need to do more to be honest inside our login so let's go into our imports and just clean up the imports as well great stuff so that's for login um what we also have to do now is the caption indicates we have to go to our notes view um and make sure that we can log out using our auth block as well so let's go to notes view here and right now what we're doing is saying we're awaiting on the auth service firebase logout so we're not going to do that anymore so we're just going to use our off block in order to log out so in here let's remove that and just say that we're saying to where we want to grab the auth block first okay so let's say context and then we're gonna read our um autoblock like this and if he asks visual studio code it's gonna it wants to import um oh yeah it wants to import auth block so let's grab off block to bring it in it also doesn't know where read comes from so um so what we need to do now is to import uh the block library in here so i'm just gonna copy that code from my notes so importing flutter block and then flatter block guard and here i'm actually drilling down inside flutter block and just seeing that i'm interested in read context okay and read context is as you can see in the code is that is the function reading here oh my god there's so much documentation here you see all right so that gives us the read functionality that we can use in here so that's the function all right after grabbing our off block now we have to convey the message of logging out in here so we're going to add an event to it and then we're going to say we add the event of off event log out just like that and this is a constant constructor as well so let's just send it send it through and after doing that we don't really have to do so much more so um and we're also not in this case we're not actually gonna go to to the login view so what is gonna happen in here i'm actually gonna remove that and we're gonna start testing a little bit so you'll see how things work okay so um i'm gonna do a hot restart in here and see if everything's working as it should so yeah what i'm going to do then let's test log out okay so in here i'm just going to say this log out and it says log out or cancel i'll say cancel so that's working as it should and i say log out and then log out and all of a sudden we came to the login view but hey wait a minute what happened we removed this code this code that was here why is why are we going to the login view without that code so this may look magical but what is happening is that since the entire application is now using off our auth block an auth block upon it receiving the log out event let's go to the off block so you get reminded of the log out event but what it is saying is that it first goes to the loading state and then if it could lock the user out and it actually says that i'm logged out now remember in the main function here we are actually listening to various events that come from our off blog and when the events that comes in is logged out we are showing the login view so it is the main uh is the home page that is doing this work so it's it is to me it is absolutely beautiful because we are like removing uh logic from our code and one step at a time so inside our login as well uh so what we need to let's go to the login view here uh let's have a look in here at login you see after login we're not telling the application that you have to go to a screen x or screen y and so we can actually test this so i'm going to say my email address here and foo bar bath and then log in see it comes to the main screen how did that do that and that's again because of the main dart you see it first said um if it's in the state of loading let's see are we handling loading somewhere no we're not using that um but if if it actually becomes uh logged in then it says display the notes view so that's how these screens are now being shuffled and displayed to the user without us having to do push routes or push name routes so fantastic very well done we've taken care of everything that we said we're going to take care of in this chapter so and what we usually do at the end of every chapter is now that you're familiar with everything you've come so far almost 40 40 chapters in this course so you should know that we need to tag our work so that we don't lose them so let's go ahead and have a look at if i can bring terminal up in here and we see bit log you can see the last commit was step 22 so let's say git commit get status first actually a whole new folder was added so we're going to say git at all and let me increase the size of the screen as well so we're going to say git commit and um step 23 okay and push these changes and we have a look at our logs get to step 22 and step 23 and there is nothing to commit at this point so let's also tag our work and we say step 23 and get push tags okay fantastic so if you look at our tags now we have 20 21 22-23 okay fantastic as this tradition at the end of every chapter we talk about what we're going to discuss in the chapter that is coming and um as i mentioned just briefly as a little note while i was talking about exception handling we've now broken our exception handling in that you see when we send an ad signal to our block our auth block um that in itself is not gonna produce an exception but right now we're treating that add function and we're putting it inside a try block and then there's on exception blah blah after that so none of those exception handling uh catches are gonna be caught so uh we're gonna handle that and fix that in the next chapter so grab some refreshments and i'll see you there hello everyone and welcome to chapter 41 of this philosophy course in previous chapters we've been talking quite a bit about uh block and um i suggested that everybody who's taking this course to have a look at block on their own time as well and to read the documentation because um i understand that block could be something intimidating for especially for those who haven't done for us this reactive programming before however it allows us to create a good separation and between our ui and our business logic as that's the point of using block in a flutter application for instance so in this chapter we're going to build up on top of what we've already done but we're from this chapter onwards we're going to spend a little bit of time to clean the logic up i mean even though things may be working the way they are right now but and there is like a saying in software development which i usually strongly disagree with that people say if it's not broken don't fix it however we've seen over and over again that things that work don't necessarily continue to work or things that do work right now aren't necessarily working to the best of their abilities so in order to make things uh a little bit better in our source code we're going to spend a little bit of time to make the logic more thorough and we have to think it more through um we've gotten started with block but we are not really there yet so in this chapter as you can see in the captions we're gonna handle off block exceptions during login so there's gonna be um quite a bit of um moving around between different files and we're gonna like basically clean things up so we have to jump around between files and i'm going to do my best to explain when i move between files as well and like what we're adding what we're removing and what we're modifying so i hope you can um you can also follow along all right so the first thing that we're going to do as you can see in the caption here is to remove our off state login failure so what we're going to do is um first of all i'm going to bring the code to the to the main screen here so you see it as well and i'm going to perhaps not even bring up scrcpy because i don't really think we need scr cpy right now so if we look at our um auth state the way it is right now i don't even know which file i opened um if i say command p off state so let's go to the off state dart file okay and as you can see in here if i if i make the size a little bit bigger you can see that we have for instance at the moment um a off state login failure and then there is an exception in there and also we for instance have off state logged in so it seems like this is kind of like a pattern that we're following so we have off state logged in and then auth state login failure with an exception and then we have off state logged out and then a log out failure however we're going to clean this up a little bit here and make sure that we don't have just like except like too many um off states that we have to handle in our application okay so what we need to do is to go into our logged out in here and add an exception so the point of this is that if you for instance um are logged out at the moment in the application then there may also be an exception and you you you probably are asking like how can a state of logout have an exception well what we're going to do is that when you try to log into the application let's let's say you're a complete new user and you haven't logged into the application before okay you download the application what you what is your state your state is logged out now let's say that you make up an email and a password and then you write that in the login screen and then you press the login button there are no users let's say in the system with that with those information that you provided then we're going to give you an exception we're going to give you an error saying that well you couldn't log in what is your state at that point well you're still logged out okay but now you're logged out and then the screen also has to display some exceptions so that's why we're going to build a build exception right into the auth state logged out okay so let's go in here and just create an optional exception in here like that and just call it exception okay and i'm going to get help from visual studio code to add that parameter into the initializer and let me do some reshuffling on the screen as well so you see it better and perhaps decrease the size of the font as well okay so that was the first thing that we had to do and you can see here that i've written we don't really need auth state loading in auth events login so what we're going to do is to go in our off block so let me just save this file and let's go to off block and in here we have this logged out with an exception and we're going to assume fix that actually let's see in here yep let's just say logged out at the moment and let's pass a null exception in here as well so i'm going to go to my notes as well to auth block to ensure that i have all the necessary information to pass through to you so let's go in here and also fix that so now we're in our off block dart file and we fixed the error that was caused by us adding an optional parameter um to our off state um logged out all right so we fixed that now then the next step as the caption indicates is we're going to remove the emitting of off state loading from auth event login so let's go ahead and do that so we're going to go ahead and remove this image from there okay so we're not gonna display any kind of like a login screen or anything okay so um as you can see in here we're now gonna start using block listener um i've talked about block listener block provider block builder block consumer before but for those of you who are not aware of what a block listener is a block listener as its name indicates and it's only going to listen to changes in the state of a block for instance our off block and it is going to allow you to issue some side effects so a side effect is for instance displaying of a new screen or displaying a dialogue or removing a dialogue or removing a screen from your navigation stack these are side effects okay so they don't necessarily create a new widget to be for instance uh to replace the current widget that's on the screen instead they can create something that is on the side as its name indicates so listener is perfect for that so the listener property or the listener parameter of a block listener doesn't return a widget except it's just a void block so it allows you to do something with the incoming state okay so what we're gonna do now is we're gonna start using block listener in our login view for this chapter in order to basically handle our exceptions because if you have a look at our login view right now you can see that we have this text button which reads login and in there we're sending an event of login to our auth block but we're also handling exceptions in this way and as we mentioned before these exceptions are never going to happen in this flow because adding a new event to your block or any block doesn't necessarily have to throw an exception the way it works for us if we go back to our auth block and have a look at our login you can see that if there is an exception what we're going to do and what we're doing at the moment is like we're saying off state login failure and what we're what we also need to do actually is to clean this up because login failure shouldn't really be there so i'm going to go to my notes as well and make sure that that yeah that seems to be completely removed so let's go to our off state actually and as part of what we did in here logged out that we added the exception let's go and remove this login failure completely okay so now i'm in off state dark file and i removed off state where was it um off state login failure because as i mentioned a login failure is now expressed by the auth state logged out all right so you're either logged in or logged out that's how i'm thinking and if you're logged out there may be an exception which was therefore for instance caused during the login process so now that we've removed that state auth state login failure in here we're going to replace that in our osblog dart file we're going to replace that by auth state and log out and then an exception in here okay so that's that so now we're talking about uh auth listeners so let's go ahead and try to fix this up so in our login view so i'm just going to go into my notes as well so if you have a look at our login view right now we have a text button at the bottom of the screen which looks like this this is a text button and it has an on press with an async okay so that is the actual login button all right and this login button is the one then for now that is going to take care of the exception handling using our block listener so as you can see in the cache it says our login view won't be rebuilt since the state is the same but with an exception so this is very important to actually understand so let's have a look again at our auth state in here and auth state logged out so even if we put an a block listener and wrap this button this text button here with a block listener and you see once the application launches in our off block you can see that first we are logged out okay so when the application launches there is no user then the state is logged out and then when you press the login button with invalid credentials for instance then the state is still going to be logged out but with an exception however this button won't be able to render or do anything with those exceptions because from our off blocks perspective it is the same state one within without an exception and the other one with an exception right so it is the same state or it is the same state class at least so we we are actually going to fix that um but for now we're just going to go ahead and do some cleanup in here so let's go ahead and as the caption indicates we're gonna handle some exceptions in our text button in here so let's go and wrap our text button um with a block listener okay so i'm gonna do command dots on this and then i'm gonna say wrap with block listener and as i've mentioned this previously i have this these wrap with block etc because i have an extension in visual studio code call call block that is from felix angelov i hope that i'm pronouncing pronouncing his name right from um very good ventures who are the people who are basically sponsoring block library so that is the reason i see all those wrap with block etc in visual studio code if you don't have that you may have to do this part by hand like to create a block listener in here but i'm just gonna take advantage of having that extension in visual studio code and just say wrap with block listener okay and here you can see it says okay what type of a block is it and i'm gonna just say it is the off block and it says what state does it have then i'm gonna say off state all right and then here it says okay do whatever you want to do now so um that was the wrapping of our text button with a block listener so that's that's just that just went smoothly now what we have to do is as you can see in the caption is to handle three separate exceptions that might happen during login let's go back let's take a trip back to our firebase auth provider um so firebase author provider dart file and have a look at our login code as you can see in here and you can see that there could be three exceptions that might happen that are called firebase auth exception user not found wrong password etc so we need to handle these off exceptions so user not found wrong password and generic auth exception okay so let's go in here and just say that okay if state is um off state logged out like that so remember inside logged out we could have an exception an optional exception and that's exactly what we're gonna handle right now so let's say if that was you see we said now if state is logged out so now in this code block in here dart is going to understand that okay anywhere in here state is auth state logged out so you have access to exception right here okay so then we're going to say if states exception is user not found off exception and we're gonna display a weight show uh error dialog so let's make this a listener also async and then we're gonna say show error dialog and which we've coded before remember this uses the generic dialog so i'm going to go back here to login view dart and for the text we're just going to say user not found okay then we have to also handle wrong password off exception so else if state exception is wrong password off exception then copy the text here and then in here we're just going to say wrong credentials and remember in anything that has to do with username and password it's quite important that you don't tell the user which part of their credentials actually incorrect because if i mean if there is a hacker who's trying to get into the system and just using the ui then if you tell them wrong password they'd be like ah so i got the email right it's just a password that's incorrect so try not to tell a user even if it's for good reasons like if it even if you even if you think well i have no hackers in my application it is still better just to say wrong credentials because the user themselves probably already know that their email is correct or incorrect so they're first going to check their email so if the email is correct then they are going to know that the password is incorrect and as you'll see we're going to later allow the user to reset their password so so just say wrong credentials in my opinion at least so and then else if state exception is generic auth exception then we're going to display a dialogue and in here we're just going to say authentication error okay so that's that part done so now we've handled those auth exceptions in our login view for our text button that says login all right so now that we have that what we need to do is to remove the uh exception handling from the button itself so at the moment we have a huge try statement not a huge actually we have quite a long try catch statements here that we have we're catching three exceptions which are now actually being caught here with our block listener so let's go and not actually do that so i want you to grab this complex read and where we actually pass the event of log into our block and remove this entire try and catch block and just do the context read at auth event login so your unpressed event or sorry on your on press parameter of your text button should look very simple just like this email password and then you pass that event to your auth block all right so now that that has happened let's actually check this out and see if everything works and remember this is like the beginning of us moving towards a better approach of handling our authentication and routing with blocks so things aren't going to be smooth actually we have a lot of problems we have to fix but this is just like the beginning so i'm going to bring scr cpy in here and let's just test this so i'm going to do a hot restart and now i'm on the login screen so okay i'm then gonna go ahead in here and like put my email address and then i'm gonna put some inquiry credentials in here okay and i'm just gonna press the login button and now you can see that our block listener is taking care of that so it's saying oh you're logged out and then it's wrong credentials okay so i'm gonna press ok then i'm gonna just put an email address here that doesn't exist and then press the login button and now you can see user not found okay and to be honest with you if you wanna if you wanna do what i actually said before that it's better to not tell the user whether it's their user that is wrong or password you may want to actually wrap both the state exception of user not found and wrong password and just display the same message so you could do that by saying war in here so or that right so and then you can just display the same message and then you could just remove this statement from there so that could also work i'm just gonna leave it like this but just so you know it is actually better to do that approach which i just showed you momentarily all right so it seems like our block listener is working fine in the login view so this was just the beginning and we have a lot to fix so we're going to fix those things in the coming chapters okay now that the code seems to be working for login view let's just go ahead and do what we usually do and commit our work so that we don't lose the the code if anything happens so i'm gonna minimize scr cpy make visual studio code a little bit bigger in here and increase the size quite dramatically let's have a look at our status we've modified three files so let's just say it's a git commit and in here let's actually let's do it at all and then we just do a normal commenting here that's step 24 okay now that it's done let's just push our changes to the remote and then let's just also gets get status nothing to command so everything was committed successfully and then let's just tag as step 24 i believe right so that's our tag and then we push our tags and let's have a look at our tags to this point 23 we have where's 24 and there is 24 so we have everything tagged successfully great so um as you can see and as is tradition we always talk about at the end of every chapter we talk about what we need to discuss in the chapter that's uh to come and um so you can see our routing and dialog handling isn't isn't block based at the moment we still have quite a lot of places in our application that we're seeing for instance navigator of context push name and removed until or we're doing push names so so we've handled some bits and pieces of our application and we're using block but for instance we aren't handling stuff in the register view or the verify email view stuff like that so we have a lot of work to do and the next chapter is actually going to be a heavy one but it's going to be such a key chapter in this entire course that if you could just stick with me throughout the next chapter then you're gonna see your applications architecture actually become more and more robust so grab some refreshments if you want to and i'll see you in the next chapter hello everyone and welcome to chapter 42 of this letter course in previous chapters we've talked quite a bit about cleaning up our application logic and our authentication logic we've come a good bit forward with that and we've um we clean up quite a bit of stuff in the login view and now we're using block listener in the login view if you follow all the chapters chronologically up to up to that including the previous chapter so you should already know about block block listener block consumer block provider um and block builder of course but we have quite a bit left and i'm actually proud to say that this chapter and maybe the next one or two chapters are gonna be like the glues that bring the application to a lot more tighter point where it will be ready for releasing to the app store and the play store so if you stick with me throughout these few chapters that are left we are going to basically create a lot more cleaner product that is not only usable by the end user but it's also but it's also architecturally sound so you're going to be proud of actually releasing this application or maybe even showing this code to your friends and colleagues so as a caption in the case in this chapter we're going to talk about moving to block for routing and dialogues because right now you know routing what we have in our application is kind of like a hybrid in the main dart file and i mean we don't have to talk about uh so like abstract concept concepts we can actually look at our main dart files so if you look here what we've done in the main dart file we're actually creating a block builder and depending on the states that are being output by our block we're displaying the correct view so this in itself is quite fine so there's nothing wrong with this but we're also mixing this up with custom places in our application where we're saying for instance context of um let's see actually with navigator off and you can see we're doing actually that's fine but you can see in our login view when you press the not registered yet register here button in order to do the registration of the user then we're doing a navigator of push blah blah blah so there's quite a few bits and pieces left still in our application that we're either directly talking with our auth service which we shouldn't be doing we should be talking to the off block or and we're talking with navigator of something to do push name so in this chapter we're going to clean these things up and make make basically our auth block and the consumption of our off block a lot tighter all right using block and listeners block builders and um we're all also going to use block consumers i believe so let's go ahead and do that so this is i mean as the caption indicates i mean i've already talked about this maybe i should have displayed this caption a few seconds ago but we've already talked about this we should basically tighten up how we're working with our um routing and our how we work with off service and you can see in here we need a few more auth events in order to be able to achieve this so let's go ahead and open our um i need to probably do some reshuffling on the screen here so you see the code better so i'll do what i usually do here and then let's go to our off event in here so these are the events that we have at the moment we have log out login and then we have an initialize but we also have quite a few other ui events that the application is doing in order to for instance interact with authentication such as um sending a verification email all right so when you're in the verify email view and the user presses send the verification email again then that is at the moment talking with our auth service directly and we shouldn't be doing that we should be asking our off blog to do that or when you for instance um ask the in in our verify email view so if you go here you can see that we had this um log out button or the restart button so let's go ahead and i'm going to bring scrcpy in here and let's actually to be able to show to verify email we have to have a user who hasn't been verified but if you remember from before if you've created a user just recently or just just now for instance and that user hasn't verified their credentials then they're gonna always be moved into this verify email view in which they have to for instance say that yeah um i am i did they had the ability to send a verification email to their email again or restart the whole process meaning to log out and just go to the registered login viewing and so that is at the moment happening directly you can see it's off service directly to the auth service and we should be doing that and then there is a navigator of push name then removed until which we shouldn't be doing either so in order to tighten these things up we need a few more events in our auth event dart file and that's what we're going to do right now so let's go to our auth event file and i'm gonna do the same thing in my notes so um the first new event that we're gonna create in here as you can see it's called auth event send email verification all right so let's go ahead and do that i'm going to get rid of this bottom view in here and also the project structure so i've already written that in my notes so i'm just going to bring it here to the to visual studio code so i don't have to write it manually but the event name should be called off event send email verification the goal is for our verify email view to send this event to our off block in order to request a new verification email to be sent to the currently logged in user okay we also need a register event so the goal is that inside register view so let's go have a look at the register view right now and you can see when the user presses the register button at the moment we're saying uh firebase create user so we're going directly to firebase auth service and we're saying create user and then immediately we're saying send email verification so we shouldn't be doing any of these so these three things that we're doing here are pretty much wrong from the architecture perspective so we shouldn't be talking with these services directly we should clean this up okay in order to achieve that we need to go back to our auth event and create a new oz event called register so i'm going to bring that at the bottom of login here so let me go ahead and create a new off event we call it class of event register and of course we're going to extend our auth event and for register we need two parameters if we go back to the register view you see upon registering we're always sending the email and the password so let's go ahead and do the same thing in here so we say final string email and i'm going to copy this and i'm going to say just password and get help from visual studio code to create this constant constructor okay you may want to make these required name fields using these but i'm not going to do that so i'm just going to leave it like this with email and password okay so that's our off event register excuse me so the other thing that we need an event called should register so um basically that means for instance if you um haven't really registered a user yet then we need to send this event i'm actually gonna have a look in my login view and that is if you for instance go to a login view in here and then you have a look at this button that we have in here not registered yet register here that is basically the event that we're going to implement right now so we're going to tell the off block that hey you should register user okay and then off block is then going to change its state to a state that the application is going to understand and automatically send the user to the register view okay so that's the use case so um let's go ahead i'm gonna just check my notes as well let's go ahead and develop this should register and i've already done that in my notes so i'm gonna bring it at the bottom of off event register but you will need to write this yourself so it looks like auth event should register extends off event and it just has a constant constructor so it's very simple okay so that was for our auth um event should register so at the moment if we go now as you can see it in caption we need also and now we've done the auth events like this stuff that we had to create in order to be able to handle various um events that come from the ui but we also need to fix up our states so let's go to our off state and have a refresher in here you can see we have the state loading logged in needs verification logged out and log out failure but we're going to clean this up a little bit and make sure that we have every state that our application requires in order to be able to for instance display dialogs or do routing okay so in at the moment in our off state what we need to do is to create you see we have this loading state and what we're going to do is to actually remove the loading state and we're going to create an auth state called on initialized all right so um let's go ahead and actually remove this off states loading and create a class in here say auth state on initialized because when you land in the application for the first time you may actually want to for instance display some sort of loading screen or whatever and we're going to indicate that the application hasn't really initialized firebase or its authentication system using this off state uninitialized it's just this is a cleaner way of indicating to the two the call side which is ui that hey we haven't yet been initialized so you need to call the initialize function on our off block okay or sorry you have to send the auth event of uh initialize auth event okay so let's go to off state so just to recap i removed off state loading and now we're going to put in our off state uninitialized so we're going to say uninitialize extends off state and let's just create a constant constructor for it as well like that okay so the other thing that we have to implement as well is to obviously we've talked about login like here login logged out and then log out failure etc and and now we actually have to start talking about what happens when the user presses the register button when the user presses the register button we also have to handle the case that yeah we are registering at the moment so it's a process that's ongoing but we also have to talk about what happens if the registration fails so we're in the process of registering either it goes fine and then we say you're registered or we say registry registration failed so let's go ahead and create a um a state in here right after uninitialized let's just say class of state what are we calling it registering extends off state okay and let's just in here as we're doing in here for instance in the state of logged out let's just copy this exception and bring it into off state registering and then let's create a constant constructor here for our off state registering and i'm just going to say constant here okay so now we have registering like that so now we have registering logged in and we also actually need to remove off state logged out failure because we well excuse me we have logged out with an exception um so let's go ahead and do that right now let's just remove off state log log out failure as well all right so excuse me again so that's for off state registering so as you can see in the caption it says loading of the logged out state we need login screen to have a loading dialog so we need is loading in the auth state logged out so let's have a look at our logged out here and previously we had this loading state as a separate state so it was off state loading and we were gonna generically use it everywhere but now what we're gonna do is to build this loading state into or to build this loading flag into existing states themselves so let's then go ahead and say well when you press the login button what we're going to do first is just to say um actually wait let's go one step back let's say you just landed in the application but you already have a user which you haven't logged them before okay so your state is logged out and the exception is null and we're going to add a flag in here and say final bool is loading and let's add that is loading to this parameter in here and make both of these required parameters okay like this and put a comma there as well like this boom so when you land in the application exception your state is logged out there is no exception so exceptions null and is loading is false because we're not loading anything then you write your credentials and you press the login button then what happens state is still logged out exception is null but loading is true then let's just say that you entered the incorrect credentials then what we're going to do in our block auth block is going to say ooh you're off state logged out there is an exception and is loading is false and then you'd be like okay now i entered the inquiry credentials then you're gonna correct those and then press the login button again now what are we gonna say we're gonna say okay all state logged out exception is nothing and then is loading is true and if then we can log you in that we're gonna produce another state for you so you see this is how we're using states to convey the cur like the correct state of the application to the consumer which is the ui okay so and this is not like you may think oh how does he know that this is the right right way of doing things well there is no rights and wrong in here it is just how you reason about your application and when i say there is no right and wrong what i mean is that some things are more right than the others and some things are more wrong than the others but what you need to find is like the sweet spot in here which is which is exactly good for your application and at the same time is not incorrect okay and that is the definition of write for your application and in this case this is the definition of right for this application so you just need to find a sweet spot for your application okay so now let's have a look in here a little and talk a little about a little bit about equality um and what i mean by equality in here is that you see what i talked about is three different logged out states logged out with exception null is loading false logged out with exceptional is loading true and then logged out with an exception and is loading false for instance so you're producing three different types of states all of the same class so how will how will uh your application understand that these are actually different states so you kind of need to differentiate between various states of your off state logged out so you kind of need to tell your application that hey although the previous state was also off state logged out and the correct like the one that i'm producing right now is also off state logged out but these two states could actually be different from each other and in what they contain so you need to kind of create like an equality and logic into your states to tell the application hey this although it's the same is like a new instance of the same state class but internally is not the same thing and for that we have to implement equality all right now there is a good package that allows you to do this in order to implement equality in your applications and in your dart code and it is called equitable so let's go ahead and import that and don't be intimidated by all these logs in here it's just because we have a lot of problems that we're fixing at the moment so let's go ahead and um i'm gonna change the screen layout a little bit increase the size and let's just go ahead and say flutter pop add equitable stuff like that and you can read more about that so i'm just going to bring up my safari in here and let's just say flutter or just pop dev and let's just say equatable excuse me and you can see it is actually developed by flutter community dev in here okay so it's a verified developer in here and you can also actually follow flutter community dev on twitter as well to get some updates about their packages okay so we're now importing that into our application and we should now be able to use that so i'm going to get rid of this bottom bar and change the screen layout again decrease the font size okay so in here now let's go and import equitable so i'm gonna just import that i've already imported that in my notes so i'm just gonna paste that in here you import equitable like this package equitable slash equitable dart okay so what we need here is we're already extending an existing class so what you can do is you can bring in equality in your classes using a mix and so we're going to say mixing e quotable mix in just like that sorry with okay so now that we're doing with that mixing now we have to implement a few functionalities in here as you can see visual studio code helps me it says create one missing override okay so i do that override in here and it says okay now we have to override this property and you can see in here what you need to return is a list of properties that have to be taken into account when the equitable package can basically calculate equality in your class and in here what we're going to say is that we have two properties in here called exception and we also have is loading so take these two properties into account when computing equality in the instances of auth state logged out all right very well done so that's that's what we've done in here so we've made our off state logged out class equitable and the reason again for that is that we need to produce various various um mutations of this off state logged out and those different mutations with various exceptions and is loading need to be distinguishable from each other okay and that's why we're using the equitable package in here so um this thing we've already talked about and we don't need the off state logout failure so we we've removed that already as part of the cleanup that we were doing earlier but if you forgot to do that please just look at the caption at the bottom of the screen just to make and just make sure go you go to offstate.file and remove your off state logout failure and the reason behind that since i explained before is that now logout failure is actually built in and baked into off state logged out class inside an exception all right wow all right let's go to the next section now well you see at the moment we have no loading screens in our application so when something happens when we're doing an api call for instance or we're um going to our off provider and say login or send an email verification we have no loading screen inside the application so there is nothing that indicates to the user that something is actually happening and we're gonna go fix that up soon so as you'll see we're going to create a new dialog which does some loading for the user and then using that dialog users going to understand that okay something is happening i just have to wait for it okay but the user experience that we have right now is kind of sub-optimal in that the user presses the login screen and dependent on their sorry the user presses the login button and depending on their internet connectivity and the speed of their internet internet connection that operation could take anywhere between a few milliseconds to a few seconds so if you're making a user wait a few seconds based on their internet connection speed then you have to kind of display to them that you're doing something well the the usual i mean way that you could do that is to display some sort of a small loading indicator for instance on ios natively you have a little loading indicator that sits on on the status bar that just moves a little bit and it's very tiny i would dare to say it's less than 20 pixels wide and 20 pixels in height kind of it could even be like 17 pixels width on height it's very little so it's a subtle indication that something is happening but that's usually i mean i find that quite annoying because when something is loading you kind of need to block the user from trying to press the same button thousands of times so if you display that little loading indicator on the top on the status bar then what you also have to do you have to add some extra logic to your application to block for instance the current register button or the loading button and you usually don't want to do that but because that's just extra logic what would make more sense is upon a user pressing the login button or the register button you want to display like a blocking screen that tells them that hey i'm doing something okay so don't do anything else while this screen is is visible on your mobile display so let's go ahead and do that so we're going to code a loading screen as you can see in the caption says we're going to do it in lib utilities dialogues loading dialog so let's go ahead and do that and bring up my notes as well i'm going to close all these files just to make sure we've also saved them because if you close a file in visual studio code at least which we haven't saved before visual studio is going to display your dialogue saying are you sure you want to close this file without saving it so it's usually good practice to close your existing files before you move into doing something new so that you at least are sure that you've saved those changes okay um now let's i mean we have some errors don't worry about that so you should now be comfortable with having errors in your application because you know at the end of every chapter we're going to tighten things up and fix things okay so let's go to lib utilities dialog lib utilities dialogues and we're going to create a new file in here as the caption indicates called loading dialog dart and you see this loading dialog what we also have to have in this loading dialog is to allow to allow the caller to display this dialog but also to allow the caller to dismiss this dialog so it's very important to be able to dismiss a dialogue when the application actually needs for that dialog to disappear so what we're going to do first is to bring a create a type f in here and we're gonna call it closed dialog let me just increase the size of that font as well and we're gonna make sure that it's equal to a void function in here okay so what we're to do in here we have we're going to create a function that displays a loading dialog but it also returns back a function that the caller can call to dismiss it so it may be a little bit of a shift in how you think about programming if it's the first time you're doing something like this but i promise you it will make a lot more sense as we develop it so let's say that we have a function that returns a close dialogue um and we call it show loading dialog okay and it has two required parameters so let's put curly brackets in here and then let's just say we have required build context and we call it build context or let's just call it context and then we have a text to display so required string text okay excuse me so and now you can see you get this required build context try changing its name and i'm going to get help from facial studio code to import let's say material okay now we have just one error saying that you're not returning anything in here so the first thing we're going to do is we're actually going to define our dialog how is this loading dialog going to look like so it's the only thing it's going to do is just to have a little loading indicator a bit of spacing and text that is going to be using the text widget to render this string so let's first define our dialogue so i'm just going to say final dialog is equal to alert dialogue like this and let's just go to the next line semicolon all right and then we have to define the content for it as you can see content should be a widget so the widget we're developing is a column because we want like a vertical list of widgets the loading screen a little bit of a size box spacing and a text widget so you can render that with column easily and remember column what what column wants to usually do is to grab as much space as it needs so it could be like the entire screen long we don't want that what we want for the column to take as little space as it needs to render its content correctly so we're going to say main access size oops exercise it should be of type main access size and we're going to say main exercise of minimum all right and its children are going to be an array of two constant widgets of a circular progress indicator like that and then we're going to say a constant of size box we haven't used size boxes before but size box is really good for um creating spacing so as you can see in here it's just an empty space with a height of 10. and then what we're going to do in here we're just going to say display also a text that renders this particular text parameter in here so like that now we're we have a little problem here with how this thing is rendered and you can see they're in the same line and that's why it kind of looks strange let's put a comma in here and then save the file to get the formatting correct and let's put a comma in here as well like that okay so now it's working as it should or at least it's formatting as it should so then what we're going to do in here we're going to just say we want to display that dialogue so let's say show oops show a show dialog okay and let's go in here and the context of this dialog and i'm going to bring it here so you see it the context is the context that we are providing to this function and a barrier or dismissable and i'm going to show you the documentation for very dismissible and let's see if we can actually find that oh it's not helping me with that but that's okay um what barrier dismissable allows you to do is to say that if the user taps outside this dialogue either allow the dismissal of this dialogue or don't and we don't want the user to be able to tap outside this dialog in order to dismiss it because a loading screen should be dismissed when we want it to be dismissed not when the user wants it to be dismissed and also for those who are ux designers who are watching this course he may be actually tempted also to for instance um provide a cancel i actually think having a cancel button in most loading screens is a good idea because sometimes for whatever reason an application may not be able to handle for instance different errors and exceptions that could occur while making an api call and i personally have been in this situation where a dialogue was displayed to the user and it was just never dismissed because something went wrong the application wasn't able to handle it so i personally as a user had to go and force kill the application and restart the entire process in order to get things working so if you want to have a cancel button in here it's fine but um i'm not doing that right now it's just for the sake of simplicity so that we can move on with this code as um as fast as accuracy as fast and accurate as possible so now you know what barrier dismissible false does and for the builder function that's what this um error is here we have to just say okay we get a context and but in here what we do is just do we remove we we return the dialogue in here okay so now we're saying show this dialogue and and then we're just going to say the return value see we still have this problem with the return value that we're not returning a closed dialogue and what this close dialogue is just going to be is we are going to return a function from our function so when the user then calls that function we're going to pop this dialog it's it's beautiful so let's just say we return a function an error function upon calling which we are going to say navigator of this context and we're just going to say pop okay so that's how you return a function that can be acted upon and invoked by others so now we save this and you can see we don't have any errors i'm going to just resize this a little bit make the font a little bit smaller so you see the code in its entirety so now let's talk about loading and exception handling during the login process so let's go to our login view and you see here we have already some exception handling and we also have this off block but we also have this text button that is doing like manual navigation it says push name and remove until and we need to clean these things up okay so let's go inside our login view and so i'm going to also do it in my notes and let's have a look at how we've done things you can see in here we have a block listener at the moment that is wrapping itself around this text button so we're not gonna do that we're gonna have the text button exactly the way it is and so meaning that we're gonna remove this block listener from here okay so what we could do is as the caption indicates we're just gonna go here to the scaffold and just say okay we have a new block listener and remember this should be the off block itself so i'm gonna say off block and this should be the off state like this so then inside the listener what we need to do is to bring what we had already um inside our text button in here so we have the exception handling okay excuse me so as the caption indicates we're going to do this exception handling now inside our new block listener on top so remove all the code from your block listener for your text button all the exception handling just cut it and bring it please up into this block listener which is at the top level all right and make this an async listener so that you can await on your show or dialogue okay so that's the first step however we still have this empty block listener in here so i'm gonna remove that now so all of a sudden you see now we have the text button in here all right that was fantastic so then what we need to do is to start handling our loading screen basically so that is going to be a bit of code so but don't be scared of that we're going to handle that soon so in order to be able to display our loading screen we also have to kind of like keep hold off this um close handle what do i mean by that let's go back to our loading dialog you see every time we call this function this is going to give us a function back so that we can close the the dialog we have to keep hold of this so that when the states change inside our login view we're going to look at that previous handle and be like oh we have a loading screen displayed to the user we have to first dismiss it okay so let's go where we're keeping hold of our email and password in here and keep hold of a close dialogue and it's going to auto import that you see so if you don't have auto import you may have to import this file yourself so let's say it's an optional and we call it close dialogue handle okay so we keep hold of that we haven't assigned to it yet but we're gonna do that soon so let's stand in here in the state of logged out and right here just add some space and what we're gonna do we're gonna say um do we already have a closed dialog handle so let's say close and dialog is close dialog hana and what we're going to do now is we're going to have a look at our states and also if we have a closed dialog handle and we're going to display correct behavior basically so what we're going to do is we're going to say if state is loading if we're not loading at the moment meaning that maybe we were loading before then our goal in here is that saying that if we are not loading and excuse me close dialogue is not null and sorry and so in this case what this conveys to us saying it says that we're not loading now but we were loading before and that the bot part is coming from here what we need to do in here then is just to close that dialog so let's just say close dialog we call that function you see and then we say close dialogue handle is null so we're just cleaning that up now okay and then we're seeing now if what we have to have so what we've handled right now is closing the dial up but we also have the hell of showing it all so we're now going to say if the state is loading and we don't have a closed dial sorry we don't have a loading dialog yet on the screen then we have to show it so excuse me so let's say if state is loading and close dialog is null then we have to show the dialogue so let's just say close dialog handle is equal to show loading dialog we pass the context let's do some formatting in here and let's just say loading just like that okay and we leave the rest of this stuff in the code exactly as it is the next thing that we need to do now is to as you can see in the caption on the screen we have to hook the register button to our auth block when register button is tap send the auth event should register to the block and what we're going to do then is go to and find this button in here at the bottom of the loading via sorry login view.dart file and upon pressing it let's just make this and yeah i don't think it really has to be any asynchronous code at all so let's just in here let's say that we grab our off block so let's say context read and we are looking for off blog in our context and then we're gonna send it an event and we're gonna send const auth event should should register just like that okay so and i believe add event is not async or anything it's just a void so this function doesn't have to be async so if you had it as async you can just safely remove that i'm just gonna save this file as well all right a lot of work we've we're kind of now almost done with uh our login view so what i'm gonna do is i'm gonna close all these files that are on the screen right now and we're gonna start moving towards also blockifying our register view so let's go as the caption says let's go to register view and having a look here at the moment we don't have and i can see in here in the previous chapters we've been working with cleaning up the login view so blockifying the login but we didn't do the same thing in register view and that's fine we're going to take care of that and i can see that by just looking at our try and catch statements in here you see these things shouldn't be in the text button so as like but one thing at a time as the caption of the yeah as i capture the bottom screen indicates we're going to wrap the scaffold inside a block listener so it's going to be very similar to how we did it for our login view command dot and grab a wrap with block listener here and i'm just going to say this is going to be the off block and it's going to auto import it for me so very important if you're getting errors for the auth block not being found in this context it's probably because you haven't imported off block so and in here we're going to say off state and that's going to also import it as well and block listener is not available in this context either because we don't have a flutter block so that's also going to be all too important so that's three so that's the three um auto imports and they're all available i believe so that's auth block auth state and flutter block so you could actually bring it next to each other if you want to so you know which ones to import it's these three wow okay um so what we need to do that that was the first thing that we had to handle so we also as i said now we have to go and start handling exceptions so this is very similar to how we did and did it in the login views so we kind of need to get rid of these so now what we need to do inside this listener of our block listener we have to handle the exceptions that we are at the moment handling here at the bottom so this should be very similar process to how we were doing things in the login view from if you remember so if we oops if i go to our login view you can see we have this uh block listener and then we're doing this kind of pattern in there so we're going to do something very similar to that except we're going to do it in register view okay so inside register view the state is i mean all the exceptions all the problems that could arise are going to be inside the um registering state so we're just gonna first make sure that we're in that state okay so let's say state is off state registering and we're gonna say if state exception is weak password auth exception then let's make this listener asynchronous so we can do an await on our show dialog so we we say await and show error dialog and the text is just going to be weak password okay and then we're going to do another else an else statement with another if and we say if state exception it's email already in use auth exception and then here we're gonna display another dialog then that says for instance email is already in use okay and um so let's then go to another else statement so i'm going to just copy this i'm a little bit lazy and i'm just going to say generic auth exception and then we're going to say failed to register so these are the various exceptions that can occur while you're registering for a user okay and you can see in here we have three uh exceptions we're handling weak password email already in use and then we also have invalid email auth exception so maybe we could actually handle that as well so let's just go ahead and add another else statement in here and just say invalid uh invalid email auth exception so we just say invalid email okay so now we've handled those four exceptions all right so what we need now is to make sure as you can see in the caption that in register view the register button to send the auth event called auth event register so let's find that register button that we're talking about here and that is this text button you can see it says register okay so what we need to do is perhaps to clean this code up at the moment there's just so much information in here that we don't really have to do so go to your register button please in the register view and just pretty much just nuke this entire try and all these cad statements the way they are so now we have a clean slate so now we have just email and password and let's grab the auth block in here and ask the auth block to do the registration okay so i'm just going to say context and let's just say we grab the off block in here okay as a function context if i can spell and then i'm just going to say add in auth events of register here with email and password just like that okay so your code should kind of look like this and put a comma in here to make it a little bit cleaner so just like that all right okay that was for register now we have also a login button in here which right now inside our register view do you remember if you end up in the registry view and incorrectly so you just tap on some button and enter them in the registry and be like oh i'm in the wrong place i want to log in actually instance so we have this already registered login here button and at the moment that's doing custom navigator or push name and remove until and it shouldn't be doing that so let's go ahead and fix that up so let's go in here and remove that code and just say context read auth block and we're going to basically add an event in here of con of type const auth event log out just like that okay so that then is going to send the user to the login screen all right all right let's move now to the next point as you can see it says send verification button and verify email view dart it should send an auth event and when you press it it should send the auth event send the email verification to the blog so i'm going to go into my notes as well as well and just find that button and now let's go in our code in here let's go to verify email view and have a look at that button that we're talking about which is right here and at the moment as you can see it's doing all service firebase and email verification but we shouldn't be doing that um we should ask our block to do that so let's just go ahead and first of all remove that code inside the buttons unpressed and then this button doesn't have to be async anymore and what we're going to say is just going to say context and read and but we don't have read remember because we don't have we haven't imported auth we haven't imported block or flutter block into this file yet but we're going to fix that soon so first of all just say read the off block and that's going to also import off block for us so that's the first part and now you have this error let's get visual studio code to import the same provider but i actually want flutter block so let's go ahead and import that ourselves so let's say package flutter block and flutter block dart now it's fine alright so let's in here and then add an event we say const off event send email verification just like that all right so it's done now so the next thing we have to do is you can see inside this restart button at the bottom of the screen at the moment it's doing quite a lot of work it is basically first logging out from our auth service and then it's doing navigation so this button is like all over the place it's taking care of authentication it's taking care of i mean i'm actually very i'm laughing here because i'm kind of laughing at the progress that we've made so far and that we've gone from very very raw programming to now very elegant handling of exceptions alien handling of routing etc so it is actually really fun to be here to be honest with you so in here let's remove that code and kind of grab this thing that we have up here in our send email verification button and bring it down here instead of sending the off event send email verification we're gonna send alt event log out like this excuse me all right so that part is done so what we need now let's go in now let's close this file and go to our off block so we have quite a bit of work now to do in our off block as you can see it's just all over the place so i want to do the same thing in my notes as well so off block the first thing that we need to do is make sure that we are not using this off state loading because we don't have that anymore what we have is off states on in each light so please take care of that as a first name so we also have now an auth event send email verification and we haven't handled that yet so let's go on top of this initialize i'm just gonna send say send email verification okay and let's create a new on to handle auth events and email verification because we haven't handled that so we have event animation here and let's just go and say this is an async function and then open it and then a semicolon at the end to get the format uh formatting working the only thing we have to do in the auth event send email verification to actually call and tell the provider that hey um we're gonna basically send an email verification all right so let's just let's just say a wait provider and email verification and then what we're gonna do we're gonna emit the exact same um state so by coming into by sending this event we are just going to do some work and emit the exact same state that you're in so we're not actually changing the state of the application because remember when you're in the verify email view and then you press the button to actually send a new verification email what happens on the screen nothing we're not like doing anything it's just we're sending the email verification that's all so we're not sending you to a new screen or anything like that so that's why we're emitting the exact same state as we had before all right now we have to actually handle a our auth event register so let's go ahead and do that so that is completely new so let's just say on off event register and we say we have the events and the emails and an asynchronous function just like that all right so when we have the auth event register if you remember from before this authentic include the email and password in itself excuse me so we can grab those and that information right now just say email is advanced.email and let's just say final password is events.password oops all right so then we're going to put this into a try and catch block so we're going to say try on exception catch e when an exception happens we're just going to emit our off state registering with that e um so we talked about this before but just to refresh when you're during the process of register we actually can emit a new state in here just called registering and then it can it can contain an exception all right so that's what we're emitting in here saying that you're in the process of registering but something bad happened which is an exception all right so in here then let's just say await provider and we're going to create a new user with the email and password they just fit right in so that's really great and then if you remember from the registration process that we had before so um in our register view during registration here upon doing a registration we didn't just register the user with the provider but we also send an email verification just to make sure that the user doesn't have to go and send an email verification and manually so we're going to do the same thing in our off block okay so let's also wait on the provider and we say send email verification just like that all right um and then after doing that since you registered a new user well what is the states if you remember from our off states off state we have this needs verification we know that when we register and use a new user that user is always going to need verification right so let's go in here and just emits that state so uh auth state needs verification just like that and that's an empty state so it doesn't have any parameters and such all right all right um then we have to handle our auth event initialize so let's have a look in here and see how the code look looks like so in here what we need to do at the moment we have logged out but you can see we're not providing that is a loading parameter and we're not providing exceptions so i'm just actually going to click clean this and write it by hand manually so in the emit let's just emit a const off state uh logged out all right so when you initialize the application from the beginning when the application actually runs we're just gonna say by default you're logged out all right so let's go ahead and do that if the user is null of course so in the exception we don't have any exceptions and we're not loading anything as such so that's like the default state so that's it comma in there and a comma here just to get the formatting working all right so that seems to be fine but we also have the initialize in here sounds good logged out it's email verified and that so yeah that looks that looks fine to me okay now let's have a look at logging in as you can see we have to take care of our login and logic a little bit and make sure that we're loading so when you say i want to log in we're going to say okay you want to log in that means you're logged out but you're logged out and there's a loading screen okay that's why we created that loading dialog which we're going to put into you so so upon the user asking to log in let's just say okay we're going to emit our const off state log out and there is no exception and the loading flag is actually true so like that and right there and just like okay so that's the loading part and let's have a look at how we're doing things in here so we have our login um and we also as you can see in here so that that was that part we've taken care of and now what we have to do is to disable disable the loading screen if email is not verified so um at the moment we have this user in here you can see final user okay and then we're just saying state now is all of a sudden logged in but that is not complete because we're not checking whether the users verified their email address or not so let's go ahead and say as the caption indicates if email not verified then disable the loading screen by sending a new logged out okay before sending the needs verification so let's take care of that so we say if um user is email verified not and we emit a constant of auth state logged out like that and we say well no exception and we're not loading all right so that disables essentially the loading screen okay by saying it's loading false remember here we sent is loading true now we're sending is loading false and then right after when the email is not verified we actually say then emit a const of off state needs verification just like that all right otherwise if the user's email is verified then we're gonna say we're gonna first disable let me bring up the correct caption so we have to do the exact same thing in here we're gonna disable basically the loading screen like that and then we're going to send this login states right here okay all right and also in our exception handling we we don't use this uh um yet we're gonna use off state logged out but we're gonna clean this up so inside emit we're gonna say auth state logged out and then there is an exception and we are not loading okay so please place that inside the exception handling of your um auth event login okay a lot of code a lot of code um now as you can see the caption that says fix fix up auth state logged out we have to emit the auth state logged out and fix up exception handler as well so let's find out our auth event logged out and we have a lot of errors in here right now as you can see so it would actually be better if we kind of like nuked this code in here and wrote it from scratch so i'm just going to say try and then we'll say on exception catch e so that's it and then when there's an exception during logged out logging out what we're going to just say we're going to say well you are logged out but an exception happened all right so let's just say um we immediate hans no actually off state logged out there is an exception and we're not loading okay so that's what you need to also place inside your code so that's for the emit now for trying what do we actually have to do we have to tell our provider to log out oops not login log out all right and then we also have to emit the new states that we're going to say you're logged out and then there is no exception so i'm just going to grab this code from there and place it in here and say there is no exception like that okay and it says well this can now be a cons so i'm gonna make it a const just like that so the next thing that we have to do is to clean up our routing because you see the more and more we're blockifying the entire process inside our application the less we need different different screens to actually do routing manually because routing is going to be handled by our block listeners and things like that okay so let's go ahead and as the caption indicates in our routes dart file we're gonna remove all routes except for create or update node route so let's open routes actually before we do that i'm going to close all the files in here just to make sure everything's saved then go to route start and remove everything except for that last route all right excuse me let's now go now that we've done that we have to go to our main dart file excuse me again and we're gonna clean up our routing in here as you can see we have those four routes now that we've removed let's just remove them from main dark file as well and save your file please so what we need also is as the caption captioning case we should show the register view if auth state is registering okay so in main dart show register view if off state is registering so i'm gonna bring up my notes as well in here so let's go ahead and see what we have we have auth state logged out what we have what we also have to have in here we have to create another else statement and say if state is off of state registering and open your curly brackets um on curly bracket missing and in here we just say return cons register view okay just like that all right that was a lot of work that we've done and now if you then look at your files in here you shouldn't you basically shouldn't have any errors okay so before testing this all because there were just so much stuff that we've done and we've also changed our main function it just makes sense to do a hot restart okay so i did a hot restart let me just resize my visual studio code so we see our trusty scrcpy in here so now this is the login view uh if you look at our login view dart file uh if you have a look at what we did when the login button is tapped we're literally telling our auth block to do this thing in here log in all right so we're sending a new event to it so if something happens to that and things don't work as well then it says user not found wrong credentials authentication error then we should probably actually get an error displayed on the screen so let's test this and you can see it says authentication error so that's in here okay so that's that seems to be working very well and it would be really good if you could actually test this um our loading dialogue and see if it works so i'm gonna write foobar bads in here and say login we saw that loading so that was our loading dialog that was this logic right here so it's it's really cool actually how it's working let's go in here and say log out and log out and then we come to the login screen so this is all working so well and you could and if you want to see your loading screen a little bit more and like if you're in the process of debugging it you could always go to your um office block in here and inside when you're asked to log in you could actually a wait so you could just do like this a weight future delayed and you could say duration and you could say seconds three something like this okay so this is gonna await like it's just gonna wait three seconds before it continues so let me just save that and enter some information in here say google okay it's our gmail and then say login oops that didn't work so well i don't know why that didn't work so well even though this is an async function could this need hot restarting maybe maybe let me do log out in here and enter foo barba sorry avant np gmail.com foo barbas and then login there we go now it's waiting more than three seconds kind of then it goes to the application so i would say that is working very well so we can now remove this weight in here okay and maybe do a hot restart as well wow that that was a lot of work we did but that's what you do with software development sometimes you break things to make them better you have to break sometimes the code that you have in order to build up something better we didn't really break things but we what we kind of did we basically removed a lot of old old code in order to make it and work better with block and i'm in this course my goal is to make you a software developer using flutter i'm not just going to show you the right thing to do from the beginning we're going to gradually make things better a software developer also is not going to be depending on their experience they're not going to do the exact right thing from point one or point zero they're they're gonna make experiments they're gonna google a lot of things look at stack overflow find the right way to do things get inspiration maybe from like another product that's kind of doing something similar and develop things one step at a time make it better so that's the reason we're in chapter 40 something right now and we've just gotten to this point otherwise we would have done this from chapter zero for chapter one so thank you for sticking uh through us sticking around throughout this chapter and coming to this point that we are right now so as this tradition we're gonna now commit our code and tag it so let me do some reshuffling of the screen go to terminal in here minimize scr cpy make the screen bigger and like that and i'm gonna shuffle the screen as well so you see things better so let's go ahead and have a look at our git status ginormous amount of things we've done everything is modified and there's a new file added so let's say git add all and let's get commit as step 25 because if you have a look at our logs the previous chapter was step 24 so now we're at step 25. so let's then push our changes now that we've committed and then we're going to say git tag and we're going to say step 25 as well so and then we're going to push our tags as well if you look at our tags now we have step 24 and then somewhere in here we should have step 25 as well as you can see here great so congratulations for getting through this chapter was one of the jumpiest chapters i would say in this entire course and that we moved so much from file to file so if you made it through then congratulations um so what we need to work on in the next chapter is our broken loading screen i know it's a little bit of an anti-climax in that we just work on our loading screen so we should be kind of proud however there is a problem with this loading screen and that is because we're using navigator of context and then we're popping remember popping inside executing pop invoking the pop function on your navigator and actually i can show you the code without going into too much details so let's have a look at our uh loading dialogue see at the bottom of this loading dialogue we're doing navigator off pop this doesn't necessarily pop this dialog it pops the current view on the navigator so even if our dialog is not displayed on the screen saying navigator of is gonna confuse the navigation stack in flutter so we're gonna have a look at that and fixing that actually in the next chapter so grab some tea coffee chocolate whatever you want to and i'll see you in the next chapter hello and welcome to chapter 43 of this flutter course we are now very very close to actually being able to release our application to the app store there are just a few things left sorry app store and play store and we have a few things left um to do before we can actually do that and um one of the most important things we need to take care of are loading screens in our application and if you remember from what we've done so far we've been working with block we've been working with our auth service and we've created an auth block and we also have loading state in some of our off states actually i can't call it loading state we have loading property on some of our off states so when our off block returns a state depending on which state it is then we can actually see whether it has it is loading property or not and we've been working with loading dialogue so far and there are just simple dialogues that we're displaying on the screen with a column with a circular progress indicator and we also have a size box just to separate the loading indicator from a text that we're displaying on the screen this has been working okay so far but as i mentioned in at the end of the previous chapter we have a bit of a problem in that if you remember from the code actually i can bring it on the screen so you can have a look here let's go to our loading dialog loading dialog at the end of this if you remember we return a function and which in turn upon calling which we pop our navigation navigator however as you can see there is no transaction in here meaning that the navigator can't necessarily know that what it is popping at the moment is in fact our loading dialogue and this problem is actually quite big in that you could for instance have a loading dialog on the screen and then while that loading dialog is being displayed you could display another screen and push that screen in your navigation stack and then if you then try to dismiss your loading dialogue what you will dismiss in fact is the second screen that you displayed in the stack so this process is not transaction based in that you're playing literally with the navigate in navigation stack in flutter and that's not such a wise thing to do so what we want to do in this chapter is to clean up our loading screens in the application and make sure that they are using overlays instead of normal dialogs so now i named overlays and it is a good time then to explain what overlays are and why they're good especially for loading screens um as you know normal screens that you display on on the mobile telephone for instance or on the web or on a desktop with flutter there it basically placed inside a navigation stack so the navigation stack is there to keep track of which screen is displayed and then which screens you can remove from that stack and so they have a hierarchy however if you want to display something on top of the navigation stack independent of the navigation stack and the various changes that could happen to the navigation stack you could use and you probably actually should use overlays either directly or using other material components that are provided by flutter that in turn use overlays so overlays as their name indicates they have they have the ability to place themselves over other content that is currently displayed on the screen so there and that makes them the perfect candidate for loading screens for instance because loading screens are usually displayed on top of the current content that the user is looking at so in this chapter we're going to focus on using overlays to improve the state of our loading screens in the application so um now before we actually get started writing the uh our loading screen um what we need to talk about is a controller uh as its name indicates a controller is an object usually that you can pass from a a function to another and using this controller usually an object that receives that controller is able to control either the contents or the behavior of the object that is being displayed on the screen for instance so imagine a scenario where you have a loading screen already appearing on the mobile device and you're telling the user wait while i'm logging you in now imagine that you want to kick off another process while that is ongoing and you want to display a loading screen again to the user while the previous loading screen is already displayed on the screen so a typical way of doing that would be for instance to dismiss the first loading screen show a new loading screen with the new content and when you get rid of the second loading screen then you can display the first loading screen again as that process is ongoing however this is quite a bit of a it is quite a bit of a race in that you have to know the previous context what loading screen was displayed before what loading screen you're displaying now if there was a loading screen before you have to display it again so it's not so scalable in that you will personally then be responsible for keeping track of the state of your loading screen so what we're going to do in this chapter is to create a loading screen that is a that is able to be controlled and its text and contents is going to be controlled using a controller object so upon creating that loading screen we're then gonna get a loading screen controller and this loading controller is gonna allow us to one dismiss the current loading screen that is displayed on the screen if any and then secondly it's going to allow us to update the contents of the loading screen so without further ado we could actually start by having a look at creating this loading controller and or loading screen controller and then we're going to use this loading screen controller where we create our loading screen so as usual i'm going to do some reshuffling on the screen so let me make the code bigger here and then the font a little smaller and let's then actually here i i'm pretty sure that we don't need scr cpy because um we're not gonna have a look at how that loading screen looks which looks like right now we're gonna write quite a bit of code and then we're gonna put it into you so i'm gonna make visual studio code full screen in here and i'm going to get rid of this bottom bar here okay so as the caption indicates what we're going to do now is to go ahead and create our loading screen controller under lib helpers loading loading screen controller and let's go in here and have a look at lib and we can see we have lib utility service access you know constant views but we don't have helpers so i'm gonna right click on live and just say new file and then i'm going to say helpers and so that you can also see it here helpers and loading and then loading screen controller so that's going to create the intermediate folders for us as well so you can see now we're under lip helpers loading loading screen controller okay so what we need here as i mentioned before is the ability for us to be able to control two things to close the loading screen and also update its contents so let's go ahead and define these type def so let's just say type f and we're going to call it close loading screen and this is just a boolean function that indicates whether the loading screen could actually be closed or not okay so it's just a function definition for now there is no implementation of that function yet so let's also go and create a type f and we're going to say update loading screen and this is a void function and actually a bool function which will also indicate whether the text could be updated and we just say text so what we're saying in here we will have two functions that will conform to this interface basically soon as you'll soon see okay excuse me let's then go ahead and create a class and we call it loading screen indicator or sorry controller and let's mark this as immutable as well and for this we need material so um actually foundation would do as well so let's just go in foundation and in here i'm actually going to say show immutable just like that so we just need the immutable part of the foundation um package in here okay so that's the definition of our loading screen controller so what it does is that it basically it takes in a closed loading screen as a parameter and we say um close and we also say final update loading screen updates just like that and i'm going to get help from visual studio code to complete this as a constant constructor and i'm going to make these parameters also required so these things we've talked about so much before so that's why i'm kind of jumping over them as fast as possible hot reload is not working so well right now it's just because the application on scrcpy is not on the screen and that's why hot reload isn't working so well so i'm going to just jump to the application and now hot reload works and then i'm going to put scr cpy on another screen so it doesn't bother us so much okay so that's our controller so we're then gonna work on creating a function that can display the loading screen and that function itself is gonna return a loading screen controller to you so that's the beauty of that function using the controller then you can close the loading screen or update it so you can see that these two are basically functions that the call side can accept and call in order to close and update the loading screen respectively all right that was the loading screen controller what we need to do now is to work on the loading screen itself so um let's go ahead as the caption indicates we're gonna go to lib helpers loading in this folder and we're going to create a new file inside loading and let's just call it that loading screen start and inside loading screen we're just going to create a loading screen class okay and we're going to make our loading screen a singleton and since we've done singleton twice before i'm just going to basically paste the pattern in here so we don't have to write this boring code again but this is a pattern that we've done so far twice as i mentioned before so you should basically know how it works so we have a private constructor then we have a factory constructor which is public which in turn uses a static final variable which in turn calls the private initializer so it's just a bit of a we could actually do it like this in so this is in order basically so when someone calls our loading screen constructor factory constructor from outside in turn calls this and this in turn calls this so it's a it's a layer base it's three layers okay so what we're going to do in here we're also going to keep pulling up our loading screen controller and so let's go ahead and send loading screen controller as you can see it's going to also import it for me so i'm just going to say loading screen controller and let's just say it's optional because we might not actually have it and um then what we're gonna do in here we're gonna have a function called show as i can see and um then we're gonna have a few more functions there that are gonna allow us to control basically our loading screen and i wonder which one is actually best to um best to work with first it could be that we should be working for instance with the show overlay function so let's go ahead and do that so let's say that we are going to have a function on our loading screen um class and we're calling it show overlay so and this show overlay is then in turn going to return an instance of loading screen controller so let's go ahead and start writing that so loading screen controller and we say show overlay and this function has a two required parameters so i'm going to put curly bracket in here a curly bracket in here and let's just say we need a build context so build contacts and it's going to auto import from material so that's great build context and require parameter build context and i'm just going to call it context and then upon you wanting to show an overlay you also have to specify its text so because what we're saying in here is that an overlay can't be displayed without an actual text in it okay and remember we're using the word overlay but in this case our loading screen is going to have a custom overlay with some material components like a column and button etc etc okay so show overlay in this case means show the loading screen with this text okay so we call it that and then let's go ahead and basically say this is a string of text just like that okay and perfect so that's fine so now what we're going to create now is um we're going to create a stream controller that will then new strings that are provided by this controller remember we created this thing so if someone updates the loading screen text we're going to put those strings inside a stream controller so let's go ahead and create a final if i can spell so we'll say this is a stream controller control controller of string okay we just create that and it can't find stream controller so i'm just going to say import lib dart async so that's another import um right here which you might have to do by hand if you don't have visual studio code or if you're not using for instance a text editor or id that can also import things for you stream controller is available in dart async so then the first thing we're going to do is to add the current text into our stream controller so this text parameter that was provided to us we're going to put it inside the stream controller okay so what we need to do is basically use a new function that we haven't used before which is called overlay of context so if i look at if you look at the return of this it will return something called an overlay state and it says the state from the closest instance of this class that encloses the given context so we need this state in order to be able to display our overlay so let's just grab this overlay of context and put it inside a state like this and then what we're going to do is since overlays are kind of displayed on top of everything else that's on the screen they don't have intrinsic sizes as such so if you're using with if you're using for instance material components such as various widgets inside your flutter application if you create different containers buttons they have some sort of intrinsic size in them however with overlays you kind of have to grab like the state of the current screen and what components are displayed on and available with the available height so we need some sort of a size to basically base our overlay on top of so let's go ahead and grab our render box and i'm going to say using this context and we're going to get find render object like this as a renderer box okay so there's lots of documentation available about what render box is but it is kind of like low level and i'm not gonna go into so much details about that but let's go actually have a look a little bit here as you can see it's a render object and it is quite low level as i mentioned inside rendering box and what it will do it will allow you to basically extract the available size that our overlay can have on the screen so let's go ahead and create a final size in here and say render box about size okay so that's that then what we need to do we actually need to now create our overlay so our overlay and you may think oh this is the overlay because we call it overlay here well it's not really because the overlay is like the over um in in this context that's overlay of is the state of the parent overlay uh context so uh what you are going to create in your application is actually called overlay entry so um but when when we say we're going to create an overlay what we actually mean is an overlay entry okay so let's go ahead and create an overlay entry in here so we're gonna say final overlay is overlay entry just like that and then we have a builder function now i'm gonna get visual studio code to complete this it needs a context all right so let's go in here now overlays they don't have a parent like a scaffold or anything so if you don't wrap your like this component that you return from your builder which should be a widget let's go in here you can see it's a widget if you don't wrap this inside some sort of a material component such as scaffold or material itself your overlay is going to have horrible styling because it's not going to have any default system styling so excuse me what we're going to do in here we're going to return a material component and material is going to allow you if you look here as a documentation of material it says creates a piece of letter i mean okay um but what it basically means it is actually let's have a look at this code maybe that makes more sense so uh is a stateful widget so it will create a stateful widget for you which has some default styling so you can put your components in there and they'll be style according to the system skin okay so let's say that we are going to give the material which is going to cover the entire screen this material component that we're returning here is going to cover the entire screen remember so let's first paint the entire screen with kind of like a dark color as you know when you display like errors or dialogues to the screen to the user usually what they do is like they paint the background the entire background kind of like a dark color so then they can display their dialogue in the middle of the screen and kind of give it kind of like um some sort of a elevation so it kind of it pops out of the screen a little bit so what we're going to do in here we're going to say color the color of our material uh staple widget in here is colors black with alpha of 150 okay and then the child of our material then it's gonna be a center okay so that's what we're gonna create here so let's then go in here and what we're going to do is the child of this is going to be container so i'm just going to create a container here and then put a semicolon there and it's happy now so then our content container is gonna place some constraints off on our overlay so it's gonna say for instance that its max width and height should be a certain value so we haven't used this before but we're gonna now use something called constraints in here and you can see the value of constraints is of type box constraints so let's say constraints and then we say box constraints okay so we're going to start with max width so then we're going to say size width multiplied by zero at that eight and what we're basically saying here saying that this this dialogue that we're displaying to the user is going to consume at most eighty percent of the available widths on the screen so this is our way of creating some margins to the right and left for those of you who are web developers and are like know about margin um and even if you're a web even if you're a designer you'll probably know already about margin so what we're saying is that this container needs to wrap itself around its contents but if the contents grow it's gonna go at most eighty percent of the available width and this width is coming from our render box okay so that's that and we're gonna do the same thing with max height so we're going to say size height multiplied 0.8 and then we're going to give it a min width of size with multiply 0.5 so we're going to say at least it should it should grab um half of the screen width okay then let's give it some decoration so we're going to say this is box decoration so let's go in here and so this is just to give it some um border so uh usually dialogues or in this case an overlay that we're displaying to use or they have some sort of a border so it creates this kind of like a beautiful elevation so if this is the dark background in here which we created with black of alpha 150 then we have an arc basically overlaying here or overlay um we call it here as you can see overlay entry then the overlay entry will be placed here but it will have some border around it to separate it from the background okay so this is just a technique to separate our overlay from the background so we're going to say the border is color white our sorry color is white and then we're going to say it has a border radius f and border radius all these documentations on the screen are just driving me crazy and border radius.circular and let's just give it a circle value of 10 in here okay sometimes documentation is just in the way so let's stand in here as you can see now we have an empty container we should never do that so let's go in here and just create a child for it so the child in here is going to be a padding so um or maybe we could just say single child scroll view for now and then i'm gonna embed the single child scroll view inside padding that's that's my preferred way of doing this so just like that and let's just give it padding of 16 for now okay so the reason that the child of this padding that we created here is a single child scroll view is as you remember we said the max height of our overlay entry is 80 of the available height on the screen that's all great and but what if your just your application display on a very small screen and then you're displaying a lot of text well if you don't put your contents in the entire contents of your material widget inside a single child scroll view then your content is going to be basically chopped so the users are not going to see the content in its entirety and what single chat scroll view does is that it tries to not scroll its contents if the content has enough space to be displayed on the container but if the contents overflows the container's height for instance then it's going to allow the user to scroll on that container so it it works perfectly trust me so let's go in here and then go and inside the single chart scroll view create a child and in here we're going to have a column and our main axis size is going to be main axis main axis size of minimum because remember if you don't give a main exercise a minimum pure column your column is going to grab as much space as it can so it's just going to expand as much as it can and if you say main exercise is minimum it's just gonna basically try to hug its contents as much as it can and then we're gonna say main access alignment is main access alignment of center so it's also going to place its contents vertically in the center okay then what we're going to do in here in column children so let's go in here and say children then let's create a size box um and give it a height of 10 so we're creating some top margin from um from top of the column so this is saying that we have a column we're going to put some stuff in it but give it 10 points of emptiness on top so it just creates a little bit of a margin okay and look i fully understand that this is a lot of abstract stuff it would be a lot nicer if you could actually see this on the screen but sometimes when you're programming especially in flutter since it's so declarative then you have to kind of use your imagination on how this thing is actually going to look like on the screen so you could do a lot of experiments and test this for your for yourself and just maybe just even do this don't do anything more than this just use a size block on the size box on the screen and just display it overlay and see how it looks like that also works okay and right after this let's go and create a our const of circular progress indicator so that's going to be a little indicator that sits there and displays that something is loading and then we're going to give it another size box with a height of maybe this time actually 20 and so this creates a little bit more spacing and then what we're doing in here we want to create a text and but that text could change because that text is placed inside the stream controller so we're not going to use a stream builder so let's say stream builder like this and our stream itself is this text um right that we created up there so what we need to do basically is to grab the stream from the stream controller and use it inside our stream builder and then i'm going to help from visual studio coding here and say that the builder function should be like and if you remember we could use a really handy getter on our snapshot that says has data so let's say return or sorry um you say if snapshot has data then we're going to return a text in here okay and the text basically is it's the text of the text widget is going to be the snapshots data as string we know that it is a string and also we are going to give it a text alignment of text align in the center okay so that's that part and let's put a comma in there as well and also we're we're getting this error right now because we're not returning a widget in all the available paths inside this builder and we have to put an else statement in here and otherwise we just can return a container as you can see in here okay so since we have to return something we could just return an empty container for now i mean you could also solve this in another way for instance say okay if the snapshot has data i'm going to return a text like this or otherwise i'm going to return a text like an empty text like this you could also try to do that but right now we're just leaving it as returning a container okay so that's that part now we created our up until this point so if i do this and fold this that we created in here which is our overlay we've just created the overlay that doesn't mean that we're displaying it so the way to display an overlay is to use that overlay of which created an overlay state and say insert overlay okay so this actually adds our overlay to the entire overlay state that flutter manages on the screen so so now we've done that so what we need to do then upon upon this happening we need to take our return statement and that's why we're seeing a red basically loading screen dart file here in visual studio code depending depending on your editor or id that you're using you may or may not see this screen as having an error but if you scroll up in here it basically tells you that well you're not returning what you said you should return so let's go in here and create an instance of loading screen um controller okay and we have to take care of the close and we have to also take care of the update but let's take care of closed first so it's an empty function and the only thing it should do is to have a look at our stream controller and close that and then we have we go to our overlay that we just created and basically remove it from the screen and also we just say yeah we returned through from this okay and now we're getting an error in here saying update it's not provided so let's go ahead and create update as well and if you remember from update uh what it does it actually takes the string as a parameter in itself so in here the only thing we have to do is to add that to our stream controller so i just noticed that you can't see the code sorry about that so let's add that and just return true and to be honest with you you could just say well let's just not return any value in here you could do that as well but i created these um function signatures so that you can also indicate an error to the call site so you may try to get rid of these yeah let's go ahead and do that if you want to but i'm just going to leave it like this in case we want to extend this functionality in the future so that we can return false if things go wrong okay all right that was the uh let's say that was our show overlay function so that's perfect so let's then go ahead and create a function in here that we're going to call also height now we have show let's go create hide okay so let's just say void hide like this and what we're gonna do in here we're gonna take our controller like this and if it's there we're just gonna say close okay remember close the way it was implemented it closes the stream controller for text and it also removes the overlay and returns true so that's gonna if there is a controller available on the screen then it's gonna return that okay sorry it's gonna close that so um and also we're just gonna say controller is null all right so and the point for us is that to show to use this function internally remember this this function is going to return this loading screen controller which we are soon going to place inside this controller variable at the moment control variable is always basically null all right all right that's great stuff so now we've taken our taking care of hide so now that we have hide let's go and create show so we say show and then we need two parameters in here two required parameters so let's say required build context build context context and then we say required string text okay so anybody calling this function has to provide these two parameters and they're very familiar because they are the parameters needed by show overlay okay so let's go in here and we say if we have a controller um if we can actually use this controller's update function in here so like this and we pass the text in here or false so now you probably are like starting to see why i'm returning true from this function and that's because well if you don't have a controller then you can't update it okay so this basically what it does it makes the code you have to write shorter because otherwise you'd have to do like this if controller not null then you would have to update but in here we're just saying either update the controller's text or else like this okay so if we could update the controller's x we just return because that means well we already have a controller on the screen a an overlay controller so we could update its text so show should just return right after that it shouldn't display a new um overlay otherwise we create and we basically create a new overlay using this show overlay and assign it to our controller our property on top so we say this is equal to show orally with that context and text all right fantastic so that's pretty much all we have to do and for our loading screen.dart file so we could just save this and i'm just going to save this file as well and close it so let's talk a little bit about our um off state and if you remember from our off state and for instance here we have off state logged out and that has a has is loading um property in here but if you look at for instance needs verification or logged in etc etc they don't have is loading so what if we added is loading to a higher level here to our off state so any off state in our application could potentially be in the loading state as well so that means registering could be loading logging could be loading whoever wants to could have loading and that's exactly what we're gonna do now so i'm going to go to my notes as well so off state let's go ahead and add these parameters that we have at the bottom of the screen to our off state okay so i'm going to say final um bool is loading and also let's say final string loading text something like this and then let's just undefine class build sorry about that i just programmed so many different languages um at final and they're so so different every language is kind of like they have their own data types and typescript has their own lowercase data types uppercase etc it's just a mishmash of various different types i just wish we could get along and have like one standard for all data types at least the primary data types in our applications but that's just wishful thinking maybe i digress let's go ahead and add these parameters to our off state and let's go ahead and do this make these required parameters so we say it's it should uh this should be provided is loading but the loading text doesn't need to be provided we'll always have a default we'll say please wait a moment like this uh and we should close this have i not closed this so like that okay so that's adding these two parameters to our um auth state and loading text always has a default string okay so let's go ahead to auth state uninitialized and add is loading in here so let's say required bool is loading so now that we've done that we should actually you see now what we're getting in here is saying that wait you're not calling your super because it's a super has this is loading parameter in here that you need to provide because it's required but you're not doing that so let's go ahead and actually add that parameter to our cells as well and say is loading and what we're doing here which is called super and we say is loading is is loading as is provided to us okay so that's for uninitialized um now let's go to registering and do the same thing in in there so we're going to say for registering we actually have exception required so let's make this required and also make is loading required so it is loading like that okay and let's call super is loading is is loading like this all right perfect that's also done and for registering let's go to auth states logged in at the moment we're getting taking the user and you see i'm making these parameters required because if you don't make them required as soon as you go to two parameters three parameters for creating a cons for constructing an object using this initializer then things start to get messy because they're not named parameters otherwise so passing three unnamed parameters to an initializer to me is just it's just a little bit difficult to understand so that's why we're making them required okay so let's go in here and make this also required name parameter required if i can spell and this user and then i'm gonna say required uh bool is uh required bull is loading all right like that and then let's call super is loading with is loading all right so that's for off state logged in now we need to also think about off state needs a verification and we're just gonna take is loading in there as well so let's go ahead and say needs verification also has a required parameter bool is loading and we're gonna do the same thing super is loading it is loading so all we're doing is that we're making sure that every state has and is loading and that is loading is passed to the super class called off state all right and then we need to take care of also our off state logged out so and you see at the moment we have a little problem in here and it says don't overwrite fields thank you dart and that means basically it's loading is already implemented on the super class so we could just safely remove it from here okay and then we say bool is loading and actually required bull actually like that and also we take in a string of um our loading text like this um so now that that is like that we're just gonna call super and say is loading is equal to is loading and then loading text is loading text just like that okay and then put a comma at the end of this perfect all right so that is basically saying that we may want to customize the off state logged out loading text because we're taking it in and then passing it up to the super whereas the others are not allowing us at the moment to customize their loading text so that's why we have string loading text only for off state locked out and not for the other classes all right um okay so that's that so we've already basically taken care of this caption as well so we've added loading text to our auth state logged out okay so now we need to save this file and just go back to our off block in here and you can see now we have a little bit of a problem in here so let me also go to my notes so i can bring up my notes off block so we have our um auth state uninitialized in here and what we need to do is say when the application opens when you the absolute initial state of the application should be in the loading state so we should say it's loading true okay so that's that part we taking care of that so i need to what we need to do now is to take care of as you say update off state logged out in off block so let's go and find logged out and we can have a look in here let's see if we have logged out anywhere yes and it says add is loading true to off state logged out while loading so um i'm gonna have a look here and see if we can actually find that so that's for instance um here and that's fine and then what we're gonna do in here we're gonna say loading text and let's say please wait while i log you in something like this okay that's off state logged out that's the first thing that we have to do and let's see where else we're using off state logged out and sorry here yes and that's fine that's fine so maybe that was the only place that we actually had to update our log state uh off state logged out i don't think we have anywhere else that off state logged out has to be set to true except for when we're actually logging you in so and i believe that we've done that now so off state logged out is there with is loading true there so that's that's the only thing we have to do okay the next thing that we have to do is to add is loading to other states in off block so let's start from where we're getting all these errors so we have excuse me off event initialize so i'm going to find that in my notes in here and in these cases when we're emitting auth state needs verification we should just say is loading false because you see when we actually end up in this state we're not loading anything we've already done the work that we were supposed to do so and that's sufficient basically in here so here we have the user so now this is a required parameter named parameter so it has its user and then we're going to say it's loading and in here we're going to say false as well so command here to make the code look a little bit better and let's then go ahead in here which is our off event login and we have this problem at the end which is off state needs verification and when we've emitted this off state needs verification is loading is also false so pretty much is loading is false almost everywhere except for when we're actually loading something which is for instance uh let's see here when we're actually logging in for instance okay so when we have the user in here we say user is a required parameter and is loading is false as well coma to make it work also and just looking up and down this file i can see we also have a problem off event register so let's go to auth event register excuse me and let's just say auth needs verification is loading is false as well and in here we have an exception name parameter i believe and they require parameter and then we say is loading is false as well so just a comma in there to get the formatting working and that is working as it should so we shouldn't have any errors basically in our offline at this point all right so then i'm gonna close that file so what we need to do as the captioning case we need to go to our login view and remove everything that has anything to do with loading so let's go to a login view and in here uh login view and at the moment you can see we have this closed dialog close dialog handle all that stuff so we shouldn't do any of that so now you see the point of what we've done is for our application to be able to handle the loading dialog just in one place loading dialogue should be handled in one place in the entire application that's what we're trying to do we shouldn't have loading states and loading like handling loading and or any dialogues and that has anything to do with loading in various views inside our application so that's what we're trying to get to okay so let's first go to this close dialogue handle and remove that because we're not going to need that anymore and then let's go in here and remove all this code inside your login view dot dart file that has anything to do with loading so now you should just have exception handling all right oh now let's go to um our main dart file and here have a look at what we have you can see at the moment we have a block builder inside the main widget of home page in in our build function we have a block builder but what we want is to issue some side effects when the state changes to something that has a loading in it okay so you see this state at the moment is off state but inside there this state could have is loading set to true so how do we handle that remember block builder is not supposed to have any side effects that's the job of the block listener however we need the block builder we actually need to return something in here we need to return different views depending on the current state but we also need a block listener so how do we do this how do we fix this well the the solution is using a block consumer so a block consumer i've mentioned this before the block consumer builds on top of a block builder and a block listener so it allows you to do both things at the same time so if you ever end up in a situation or application where you want a builder a blog builder and you want a blog listener block listener at the same time there is where you need a blog consumer okay so let's go in here and say that in our main file i'm going to go to my notes as well and i'm just going to say excuse me in here we don't have a block builder instead we have a block consumer and now we have listener in here and let's grab hold of this so what we're going to do in here is say if state is loading then what we're going to say is we're going to say loading screen and it also imported for me okay and then we're gonna say show okay we have the context already and then we either take the state's loading text or we say please wait in a moment so if the state's loading text is not available we just use a default one in here so if the state is not loading we just say loading screen dot height all right so that's that so now that we've done this this is pretty much like the last building block that we have to build inside this um inside this application for now so i'm just going to close this main dart file and resize the screen let's go ahead and bring up scrcpy and if i dare i'm gonna hot restart the application entirely because we've done so much new work and let's go ahead in uh just for experiment i'm gonna go into what is it loading okay i'm just gonna go into our provider in firebase auth provider inside this login if you remember from before it user login in here like this we could basically have a little bit of a delay so because otherwise we may not actually see the our little uh overlay so i'm just gonna first not do that and try to log in normally so fubar bass you saw did you see our little overlay there so i'm going to log out now and see if we can see it what we didn't but if i try to now put a little bit of a delay in here so i'm just going to say await um future delayed the rate const duration seconds three and just hot restart the application and then i'm going to say my normal credentials foo bar and press the login button and this is our overlay right and it has the ability for you to actually update its text as it's displayed on the screen so then yes everything is actually working as it should so now we have an overlay we don't have our loading dialog anymore so you could safely basically go and say well i want to get a complete rid of the loading dialog so i'm going to leave that up to you as now that we did we don't need the loading dialogue so what we achieved in this chapter is actually huge because we now have a loading um screen that is independent of the entire application and it's in just one place that's the goal we don't have many different places in our application that are handling the loading dialogue okay so let's go ahead and make sure we're not going to lose our code our precious code that we've written so far so i'm gonna rid of i'm gonna get rid of scr cpy increase the size of the screen and let's go as we usually do and commit and tag our code so if you look at our logs the previous commit was step 25 let's add everything and say git commit step 26 i'm going to push these changes and let's just say git tag step 26 as well and then get push tags if i can spell but if you look at our logs now so we have step 26 in here and if i scroll a little bit step 25 is before it and all the tags are also available in here you can see 25 and 26 available right there all right so we've done what we promised to do at the beginning of this chapter and we created a great overlay that we can reuse in the in the application and just show and hide only in one place so what we need to do now is the very exciting stuff in that we're getting really close to being complete with our application so we have login register verification email verification we have loading in screens we have sharing deleting it's just we have pretty much everything for application but we still have some little bits and pieces left to make the application more useful because remember when you create your application and send it to apple and google for review there's actually going to be real people who sit there and interact with your application to see if they can make sense of it so we need to clean the ui up so that it's a little bit more user friendly and that's exactly what we're going to take care of in the next chapter so i'll see you there hello everyone and welcome to chapter 44 of the swata course in previous chapters we've been basically working quite a lot with block and we've been making sure that our applications loading screen is working so we have one place in the entire application that we're taking care of the loading screens and we also have wrapped our whole authentication process inside a block and we're very now close to being able to release our application to the app store apple's app store and google's play store so this is usually what we do as software developers just before releasing our product or we basically go and clean it up as we say so we put some final touches to it so even if you're a designer you usually do that probably like if you're working with figma or you're working with sketch you first are like designing your product and then before you present it to the product owner or the developers you probably put some final touches to it so um that's what we're gonna do in this chapter and we have um a few things also left to do which have nothing really to do with the final touches to the ui it's mainly to do with the products functionality and we'll talk about that first so if you think about it what we have at the moment is um an application that a user can register they can't send an email verification they can log in and they can go into the list of notes that they have they can create notes delete notes and edit and share notes however we haven't really exposed a functionality for a user to be able to reset their password so imagine a process imagine an application where you've created it created a user in the application and you forgot your password and there's absolutely no way for you to get back into the product or the software and because you just don't know your password so you may then have to personally contact the application developer and say could you reset my password so it's a very very difficult process to do manually and you shouldn't really do that so what we're going to do we're going to do in this chapter is not only to do final ui touches but also we're going to create a password reset functionality into our application so let's get started with that i'm going to do some screen reshuffling in here as you can see in the cache we're going to go delete all users in firebase console and also all their data so i'm going to bring up console firebase.com and i'm going to bring it to the main screen in here let's find our application i believe it's this one and i'm then gonna go in here to a firebase date the firestore database and let's start by going in here and deleting these documents so let's say delete document and we have four documents so it's nothing so difficult to do just one at a time we delete these documents okay here here and those are our documents gone so you could just keep your collection i think it's best because our application at the moment is assuming that there is a node collection available if you remember from our node service so that's that part we deleted the data but we haven't really deleted the user so let's go off to authentication section of your firebase and in here i'm just gonna say delete account and let's just delete this account as well so now we're basically starting off fresh so no users and no data in the entire and back end all right so that's that part let's do that i'm going to then bring up our source coding here let's see so here we have our my notes application as we've called it so that's visual studio code i'm going to resize it a little bit and then i'm going to bring up scrcpy as well which has our app running at the moment and the application thinks at the moment that we're logged in because it hasn't really communicated with the back end yet so i'm gonna just do a hot restart in here and this is this is the problem that you'll sometimes actually notice in the in your application in that firebase isn't gonna immediately understand that this user doesn't exist on the back end anymore so if you delete a user from your firebase backend it doesn't necessarily mean that it's immediately going to be reflected to the application so let's see what happens in here if i then log out with this user like this and then try to log in with a user that used to exist in the application but i just deleted it foo barbado and let's see what happens in here and now you can see we see we say user not found okay we're gonna clean up that message as well soon in this chapter so good we have a clean slate now so we have no users and no data in the application um so what we need to do now is to start by defining our events and states for forgotten password okay so if user says hey i forgot my password we have to have an event so that we can send that event to our um off block so you can see in here we have to go to auth event dark file and add an auth event for god password okay so let's go ahead and do that so i'm going to open off event dark file and perhaps over log out in here we're just going to say class i'm going to increase the size in here as well obviously better class um off as we've said in the notes here off event forgot password extends off event okay just like that and in here we need to grab the user's email so we say email like that and i'm gonna create a constructor for this as well just like that and let's just make this or here with curly brackets okay all right so it's a name parameter now um and we just said auth event forgot password fantastic so that's that part um then we also need to go and define a state because when a user presses a button for instance saying i forgot my password then our off block is going to produce that state and say hey application that your state right now is forgot password and then in the main dart file as you'll soon see we will go and edit and add that state to our state handling as you can see in your main dart file the moment we have all these states but we're going to add a new state that says else if state is off state forgot password then display a forgot password view which we're also gonna develop soon so as the caption indicates let's go and let's go to the file off state dart file and i'm going to do that in my notes as well after registering it really doesn't matter where you place that code i'm just going to place it here after registering and just say off state forgot password and off state um and then we have to also take care of this so what should the state actually indicate to the application let's say that when you're in the forgot password view which we're soon gonna develop um there could be two things that you wanna convey to the user in that screen either the user has just landed so there are actually three three states that that screen can have either the user has just landed on that screen meaning that there is no errors nothing we haven't done anything so it's just a clean slate so that's the default state of off state forgot password so nothing okay however what if the user has actually pressed the um send reminder email because you see the way we're going to handle for a password is we're going to actually ask firebase and say firebase this user forgot their password with this email send a reminder email to them or send some kind of like an email to them that they can't actually reset their password so upon user pressing that button to send a reminder email to their email address um a few things can happen actually two things that we're going to handle one is that well we tried to send an email but it didn't succeed so kind of an exception so that's the second state remember no state second state is there's an exception and there's a third state that there was no exception but we've actually sent the email so three things we have to handle okay so the default state with no values is state number one nothing has happened state number two would be actually having an optional accept exception here and the third state is um bull has sent email like this okay so let me go ahead and create a constructor for these i'm not gonna explain this again because we've talked about this quite a lot and i'm gonna make these required parameters okay just like that and put a semicolon at the end and in here we're just gonna call em we're gonna call super but remember from super off states has a constructor here that has to provide is loading okay so in in this case let's just actually take a bull is loading as well as a parameter in here and then we're gonna pass is loading to our super as well just like that all right so when we're actually working with this auth state for that password we can actually give it is loading parameter and that's going to get delegated back to off state so our main dart file is going to be able to display a loading screen if is loading is true if you remember from main dart file we have this beautiful block consumer with the listener that that looks at any off state and as long as this auth states is loading parameter is true or that auth states is loading variable or property is true then it shows the loading screen all right perfect so now we've taken care of off state so we didn't make any changes in main dart file yet okay all right what we need to do is now go to our um auth provider dart file and define an interface function for sending a reminder email so i'm gonna go and do that right now auth provider i'm gonna do it here as well off provider okay so let's go ahead and define a function that every auth provider including our firebase auth provider has to conform to okay so let's say this is a future point and we call it send password reset like that and we have a required string parameter to email just like that so this is now defined after defining this you'll understand now soon that we have a few errors because auth service conforms to auth provider and so does firebase auth provider but we're gonna fix these soon okay so as the caption indicates let's go to firebase auth provider in here and actually implement that so i'm gonna go to firebase off provider in my notes and i'm also going to go here on the screen and say um firebase off provider and you'll see an error in here in visual studio code you can actually get help from visual studio code to complete that missing overwrite for us you can see create one missing override and this is basically saying that you're conforming to auth provider but you're not actually overwriting all the functions that boss provider wants you to override okay so if you're working with vim or if you're working with sublime that doesn't for instance have dart's um plugin then you may have to override that function yourself but the signature of that function is very easy you can just go to auth provider and grab this function and just put a override before it okay so that's completely fine as well but since i'm working with and this is asking me to save this file but there's pretty much nothing that i did in this file already okay so since i have visual studio code i can ask it to create the missing override for me and it's gonna probably create it right at the bottom in here okay so that's fine so let's put this whole thing into a catch block so i'm just gonna say catch like this all right and then if anything happens during this process of sending a password reset email to the user we're just gonna throw a generic auth exception in here okay so then um and also if you're wondering about this syntax this is just like you ignoring an incoming variable in swift and in rust and some other languages like python you could also do something like this that you ignore an incoming variable using underscore but in dart it's not really you ignoring ignoring the variable it's you naming the variable underscore but i try to sometimes use this just to indicate that hey i don't care about this variable okay but just know that internally you're not ignoring it you're just naming it underscore okay so let's go in here and and now ask our provider so um so we just say await since we're in firebase auth provider we can actually say wait firebase off oh and we have to mark this function as async otherwise we can't use a weight and then instance and then there's a function called send password reset email and it it says to which email and we're gonna say to this email okay all right so that's our catch in there but we also have to have another catch that is that catches firebase off exception as we're doing in many other places so let's have a look um here for instance okay so let's go before this catch and say on firebase off exception catch e something like that and then curly brackets and curly brackets close so i'm going to bring this code up so we see better so there are two things that we have to handle two codes that we have to handle as you can see we're handling a few codes in here for instance user not found wrong password and these things are basically i haven't really found the correct documentation for these things like where firebase has documented that these errors are going to happen with these codes it's mainly that i found them out through experience just like trying different things and seeing that things fail and upon failing i caught their error code and now i know which error codes i had to actually have to handle but if you search on google i'm pretty sure you're gonna find some good documentation about a firebase and the google team are great at documenting things so so one error that we have to handle is called firebase auth invalid email and the other one call is called firebase off user not found so let's first grab the um error code so i'm just going to say switch e code in here because remember any firebase auth exception that comes from firebase has a code of type string as you can see here and that's that string that we're interested in so let's handle firebase auth invalid email for now okay and then in this case we're just going to say throw um invalid email off exception oops we already have this defined from before okay in our off exceptions here dark file you see and the other case that we have to handle is called firebase auth user not found so it's a user it's like anyone asking for a reminder email for their password and that user just doesn't exist in the database so then we have to handle that case as well it's called user not found just like that okay and then we're gonna throw a user not found off exception in any other case of firebase authexception we're just going to throw generic off exception just like that okay and we're going to save this file fantastic so we fixed firebase auth provider but if you look at your project explorer you still have a problem in auth service because if you remember auth service also implements auth provider but it delegates all its responsibility to its auth provider so let's go into our auth service and implement the send password reset functionality so i'm just going to go in here and get a visual studio code to complete this with command dot on mac or control dot and linux and windows and just say create one missing override okay and in here i'm making this an arrow function because i believe every other function we've done in here is an error function since all these functions inside all servers as i've stated before basically delegate their functionality to the provider which is given to it inside its constructor so let's go ahead and create an error function and in here just delegate this to the provider and we just say provider send email verification and in here we just say um send password resets actually called sorry provider send password reset to email to email just like that all right and let's just save this file then um [Music] so what we need to do now is to actually handle our auth event for god password in the off box so i understand there's lots of like jargons that are flying around here so you may just be a bit confused about okay what are we actually doing so what we need to do now is you see soon what we're going to do is to create a little button in here and say forgot password so when the user lands in the login screen they may be like okay this is my email but i actually forgot my password so they have to have a forgot password button somewhere here upon them pressing that button in the login view we're gonna send this event to our off block so if you remember from our off event so i'm going to go back here you don't have to go here if you go to our off events you can see we have an auth event forgot password so the goal is for our user and for for our user interface to send this events to the auth block and then off block is going to calculate its state based on that okay so let's go now into our auth block file here as you can see and i'm going to do that here in my code as well and we're going to go and implement um this functionality here forgot password like this and let's go and say on off event forgot password just like that and you now should be quite used to this syntax emit and this is going to be asynchronous function and just uh curly brackets just like that so this is like the bare bones of handling an event in your block okay now we're handling off event for a god password so what we're gonna do in here is we're just gonna say uh by default we're emitting a constant off state for a god password exception is null has sent email is false and it's loading is false so what we're basically saying in here is saying by the user pressing the forgot password button what we're doing is saying yeah go to the forgot password screen that's all that's all we're saying okay because then our main dart file is gonna handle this it's gonna say okay if this date is forgot password i'm just gonna go to the forgot password screen okay so then what we're gonna do is we're gonna extract the user's email from this event if there is an email in there it means that the user was in the fargot password screen and actually press the button to send a forgot password email to themselves okay so if that's not the case then we know that all the user did is just to go to that screen so there is no email to handle so let's just say final and if i can spell oops final email is event email and we say if email is null then we just return meaning that yeah the user it seems like the user just wanted to go to the forgot password screen okay so that's that's that now if that is not the case so let's just put a comment in here user just wants to go to forgot password screen and if we end up in here in line 21 for me user wants to actually send a forgot password email okay and in this case let's just emit the exact same state as we did before but in this case we're saying loading okay remember our main dart file is going to catch all the states that have loading and actually display our loading screen or the loading um overlay okay so that's that part but then what we're gonna do is let's just go in here and we have to actually say in here do a try catching here so we say cat on exception catch like that and since we're in our off block we have access to our provider so let's say we wait for the provider to send a password reset to the email just like that okay and then we have to enable two variables in here we just say boolean did send password or set bits and email and just like that and we also have an optional exception like this so the goal is we have a try and catch block in here and in the try we just say yeah this email was sent successfully because yeah if you don't end up in the catch block meaning that there's there was no error then the email was actually sent successfully and we will also say the exception is basically null so we don't have to worry about any of those uh functionalities um after this point but remember we are basically saving these two variables in here so that after the try and catch block we can actually emit an aust state for a password with those variables so this thing is going to go in here in oh the documentation it's going to go in here and this thing is going to go in here okay and it's loading is going to be false so that's why we're basically storing them in here so in the positive case in the happy path as we call it we're going to say did send email is true and we're gonna say exception is no okay and in this case that's an email it's gonna be false and exception is gonna be e all right so we store those and let's just then copy this state from above and let's just paste it in here so in this case we say hey the exception is the exception if any um invalid oh yeah it can't be constant if it's a variable so um let me bring it here again so you can see exception is the exception like that it has sent email is going to be it send email and um is loading is false so that's it now we are emitting that state to the application all right so after all of this you see if and now that we've handled that event and the state in our offload we also have to display some sort of a dialogue to the user so if you're on the reset password um screen and you enter you've entered your email and you say hey send me a reset um password email after you've done that we're then going to display a little dialogue to you and say hey okay we did that we've sent any error an email to you go check your email so we basically need a dialogue and if you remember we have a generic dialogue already so we're just going to reuse that okay so let's go ahead as the caption at the bottom of the screen in the case go and create a file under lib utilities dialogues called password reset email sends dialog so um let's let's go ahead and do that under i'm gonna close this file as well have a look at what we have in here and we have utilities excuse me dialogs i'm going to create a new file in here and just going to call it password reset and email send dialogue dot dart okay and so that's the file and we're just gonna say this is a future void um show password uh reset sent dialogue all right so it's a function that just needs a build context and we're going to get an error here simply because um i believe oh visual studio code imported build context for me automatically that was fantastic okay so we're just gonna return show generic dialogue okay and you can see this is also gonna be auto imported we've already had this function from before so let me put a comma here and a semicolon at the end just to get the um dart formatter to format my code and i'm just going to in here say this is a generic void function okay and for title we're just going to say password reset like that with a capital r and the content is also string we can say we have now sent you a password a reset link so like this please check your email for more information something like that okay and you can change the string if you want and for the options it's an error function that has to return a map and it has only one button with the value of null and that's it okay all right so that's our show password reset sends dialog um now what we have to do we also have to develop the actual view for password reset so as the caption at the bottom of the screen indicates we're gonna go to lib views and we're gonna go here you see lib views and under views we're gonna create a view called forgot password view so let me go ahead and do that forgot password view dot dart okay and i'm gonna go into my notes as well i forgot the password view okay but we're gonna create a stateful widget in here so that's actually quite a bit of code that we have to we have to write but we're gonna take care of that so it's not a problem so let's go to forgot password view and the first thing i'm going to do is to create a stateful widget with stf in visual studio code i'm just going to call forgot password view just like that and since we need a text field on the screen and so that the user can enter their uh email address just like we're doing in the login view let's go ahead and create a text editing controller but before all of that we also have to import materials so that we get rid of all these errors that are on the screen right now so let's go in here and just create a text editing controller so late final text editing controller and let's just call it controller and you remember this pattern from before so i don't have to explain it again so we go into init state inside in its state we create the controller so we say it's a text editing controller oops text editing controller and in dispose we just dispose of it basically so controller dot displays okay so that's just a boilerplate there's nothing magical happening in here we're just preparing that view okay so what we need to do also in here we're going to create inside this build function we're going to return a block listener because based on the various states of auth state forgot password so let's go to auth state or god password here based on various states of this we may have to show or hide different things for instance if um if we know that the has sent email boolean flag is true then we're gonna basically clear the text fields value using the controller's clear function and we're also going to display that dialogue that we just wrote has sent email blah blah dialogue it was a long name it was let's see in our dialogues uh where is it in our dialogues if i can find it it should be under utilities dialogues and then we we should be called a password recent email sends dialogue okay so we're going to display that and that is why we need a listener so inside this build in here what we're going to do is just going to say we return um a block listener and this needs to be auto imported as you can see and this block listener actually listens for off block which also needs to be auto imported so there's lots of imports and if you don't have a good text editor like visual studio code unfortunately you'll have to import all these by hand and that's just a huge time waste direct oxy so i don't usually give advice but um my advice here at least because i think it's so important is to get yourself a good text editor because it makes development a lot easier if you have like visual studio code so we have off block and then the second and generic parameter is off state which also needs to be auto imported so there's if you look at the top of the file there's quite a few um imports already that i didn't have to do manually and so we have a listener let's get help from visual studio to complete the listener and we also have a little um let's see we have a child in our block listener that we can return so in here for now let's just say we return a scaffold as a constant all right so but we can now work on our listener first so inside the listener the only thing we're the only state that we're interested in because this is going to return any off state to us as they change we're only interested in um if state if i can spell is off state forgot password so that's the only state we're interested in and then we say if state has sent email then we're going to control go to controller and say clear and then we're gonna await on and displaying the dialogue so async and then we're gonna say await and i forgot the name of our huge file in here again utilities dialogs and password reset email so i'm going to grab this the name of this function at least okay so i grab the name of that function paste it in here and get visual studio code to auto import it for me okay and in here the only thing we have to do is just to pass the context in there so if the email was sent the password reset was sent and we're going to say clear the text on the screen on the controller and then show the dialog telling the user hey we sent an email to you okay however if there's um exception like this then what we're gonna do is to display an error to the user so we're just gonna say await show error dialog and i think that also got auto imported again you see so then we're going to say error dialog with that context and then we're going to say we could not process your request please make sure that you are a registered user or something like that um and we can say please make sure that you're a registered user or if not and a user um or or if not register a user now by going back one step okay so this is just some text i mean you don't have to write this text it's just basically saying that if you're in the forgot password screen and you're saying that hey i forgot my password it's my email if we can't find that email if there's an exception for instance then um we're gonna display this message and say hey you may not be a registered user do you want to go back and register yourself so and remember in here you could be you could try to be more fine-grained because remember our exceptions in here off state exception in the case of auth state forgot password if you go to our off block um off block in this case remember the exceptions come from the send password reset so this send password reset if you go to our firebase auth provider send password reset oh my god where did i end up um no firebase auth provider in this case those exceptions could be invalid email or user not found so you could actually try to be clean and in your auth sorry in your forgot password view and actually check what kind of exception that is so i actually think it's it's better if you do that i'm not going to do that in for the sake of just saving some time but you may decide to go ahead and do that and i encourage you actually excuse me to do something like that if you want to so what we need to do now um is we've done the listener so that's really good but in the child we actually have to create um we have to create a um proper scaffold so let's go ahead and remove the consonant in here because at the end we're not going to end up with a constant scaffold it's very rare that you'd end up with a constant scaffold and in the app bar i'm just going to say we have an app bar in here and it has a title and the title is just going to be constant text and we're just gonna say forgot password okay some commas in there to get the formatting correctly and in the body we're gonna create a column this is what i usually like to do create a column and then i'm going to wrap it in some padding like this and let's just say padding of 16 as well okay so then that's that's basically our main focus in here so we need to work on a little column in your forgot password view so now we have that as the first child of the column we're going to add a little const of text in here and to tell the user actually what they should do in this screen so let's just say and i'm going to grab the text that i had prepared from before and paste it in here so i don't have to actually write this thing again so uh let's see why is it complaining what is the actual error um too many positional arguments okay i've messed up something in here right of course because in the column i added actually didn't say children so let me remove this children inside the children first i'm going to put this text okay so if you have the same problem like me it's because you place the text right inside the column and that's not okay we have to put it inside children property of the column okay and we're going to create a text field right after this where the user can actually enter their email address so let's say text um text field and in here let's see yeah but we don't have a comma at the end of this either so i'm going to put a comma in here okay text field so the screen looks a little bit scary right now it's just because it thinks that it has to be a constant but it's not a constant so these little warnings are gonna soon disappear okay so let's say keyboard type and it's a text input type so i'm gonna say text input type email address okay autocorrect on email fields always has to be false okay you don't want autocorrect on email fields it's very annoying and we autofocus as well so that when the user ends up on that screen the textville is automatically focused on and then we put a controller and after this the problem with the constants is gonna go away so that's fantastic um and then let's just go and create a little decoration with a hint so we just say const input decoration and we're going to say hint text is your email address like this okay so that's that part now we've created the text field after this we actually need to have a text button we actually need two of them so i'm going to say text button [Music] like this and inside the text button on the first one it's going to it's going to be the actual cta call to action meaning that when the users enter their email address then they're going to press this button and this upon pressing this button we're going to send the email to them okay so let's say i'm pressed and this is an empty function just like this for now and its child is just going to be const of text and we're gonna send send me password reset link like this so that's the first i'm gonna copy this text button actually and paste it again right after that and in here we're just gonna say back to login the login page and in here we actually have this functionality from before in our auth blog so let's just go inside this and say context read or off block from the context and then we're gonna add an event in here and say off event login so actually sorry log out so this is gonna send the user to the login page okay so that's the second button handle already and in the first button let's just grab the user's email so let's just say email is controller text and in here we're then going to tell the off block that it has to send a password reset to this email so we're just going to say context dot read off block from the context and we're going to add and we're going to say off event forgot password and the email is email just like that all right well that's it actually in this case maybe yeah it's cleaner not to have a comma in there because if i put a comma then it formats a code like this but without having formats like this which to me in my opinion is a little bit cleaner okay so i think now we've implemented that so this screen should be ready our forgot password view so as a caption now at the bottom of the screen in the case we need to go and look for the off state for god password and return for god password view in main dark file so i'm gonna go to main dark file um [Music] so let's let me close this and close this and let's go to main dart file and we are handling already quite a lot of states and right after here login view excuse me let's then say else if state is off state for a god password just like that curly brackets and in here then we're going to say return const forgot password view and this is going to be also imported as well okay so that's it oh um that's that's that part uh our forgot password and what we also need to do is to make sure inside our login view so let's go into our login view now we need to have a little button in here that allows the user to go to the foreground password view so we're gonna add that in here so i'm just gonna create another text button so copy the text button that you have at the bottom and paste it in between in here okay and in this text right now we're just going to say i forgot my password like this and in here let's just send off event for that password okay so now if i press the command s button to hot reload you can see i forgot my password displayed here and we press it and at the moment actually nothing is happening it's probably because we changed our main dart file and we haven't done hot reload so sorry hot restart so i do a hot restart now and i say i forgot my password you can see we end up in this screen that we just developed and then you have the avail ability to send a um reminder email and if you say back to login page then logout is sent and you end up in here okay so that is working now um now what we need to do also in a login view dart in here so let's go to login view dart and have a look at how we're handling this user not found at the moment and we have just user not found but if you think about it there is going to be people from both apple and google who will test your application when you send it to app store and uh google play store so just saying user not found is a little bit it's i don't want to say it's wrong but it's just not fully encompassing what could what the problem could actually be so saying user not found is like the bare minimum of what we could convey to our user so let's just make that better by having a little bit better text in here so i'm just going to write this text that i had from before so we it's better just to say cannot find a user with the entered credentials okay just a little bit better message as now that we're we've basically done the forgot password where we're going into the cleanup state so we're adding some final ui touches to our application to make it look better so as the caption indicates let's go into login view and add a padding in here you see we just have a column and it kind of looks like edge to edge it's not so professional so let's just add a padding in here i'm just going to say wrap with padding and we're just going to say padding of 16 in here okay so it looks a little bit nicer in my opinion at least looks cleaner okay even if you're doing website development you're inherited um for instance elements on the screen they have like your user agent has some padding already or margins built in to inherited widgets it's our inherited element so um unless you go and change your css so this is kind of us adding that um padding in our elements in the flutter application so the next thing that we need to do in here you can see in the login page at the moment it's just on the top says login and enter your email blah blah but it doesn't actually give the user any instructions you see here in the i forgot my password we're giving the user some instructions on what he or she has to do but in the login page we're not so let's go ahead and remedy that and just add a text on top of the screen i'm going to paste that text from what i had before inside the children of this column and we're just saying please log into your account blah blah and you'll see now that appear here just makes it look a little bit nicer in my opinion and we've already now fixed this and going from the login view to our forgot password we've already added that in here as you can see so this element at the bottom of the screen this caption is already addressed we don't have to do anything special about that now let's go to register view as you can see our have you broken the register view not registered yet i can see that that button at the moment isn't working so let's see what we've broken event should register okay and inside our off block event should register i can see we haven't even handled off event should register so that's we need to definitely do that right now so let's go to off block and um have a look at handling our um i'm gonna remove this caption right now because that's not what we're working on right now so let's go to our off block i'm going to maybe actually add that so um as a caption so that it is clear what we're working on right now okay so let's go to our auth block and say on this event and let's just say event and emit just like that and what we're doing in here is to say we're now emitting constant off state registering okay and there is no exception and there is no loading so false just like that okay and a comma here to get the formatting working so now let's press hot restart because remember you're changing your auth block which is being provided in your in to your entire application in the main dart file so main dart here so you can see in here it's the block provider that is basically creating the off block so if you change anything in your off block you may actually have to do a hot restart okay for those changes to take effect for app for entire applications so not registered yet pressing it goes to the register view okay so as the next point that we have to handle here is to add some padding to our register view as you can see in here our register view at the moment looks like this we have the register button and already registered button buttons right here but we don't have any padding around our register view so let's go ahead and take care of that so i'm going to go to register view here and let's go ahead then and wrap this column that is at the moment in here and just say wrap it with padding as the caption at the bottom of the screen says we're going to add a padding of 16. so you can see now we have some padding in there and soon just like in the login view we're going to add some text to the top of the register view so what we need to do is just to ensure that deleting that their text inside this column is actually pat it's and it's basically sticking to the left side of the column because by default all the components that you place inside your column are vertically aligned and no sorry they're horizontally aligned in the main axis of your of your um column so if you that's what i mean like if the column what i mean is that the column is expanding to the entire space uh real state and then all the components that you're placing inside your column they're horizontally aligned in inside the column so that's actually a better way of probably saying it so and what we need to do in here let's just go and say uh inside the column as you can see in the caption at the bottom screen we're going to say cross axis alignment we're going to say cross axis alignment start if i save this and go back to the register viewer you're seeing this in here basically like that and what we're going to do then is to um is to add a title to our column so i've already added that before so let me bring that up so uh i'm going to add a little title to the first item inside the register view so it looks like this but we also now that we've done that i mean we want our text field to be left aligned that's why we added this cross access alignment but we've kind of messed up the alignment of our buttons in here so we need to kind of wrap them inside centers so what we could do is to inside you see we have two elements in here but we don't want to wrap both of them in their own centers so what we could do is just to say wrap um this text button inside a column then we put the other text button also inside the column right here and then we will wrap this column inside a center so wrap this column then inside a center just like that so if you go back to our register view now we have a nice little layout displayed there so we've taken care of that we've taken care of the title of our application and what we also need to do is to make sure when we come to the register view um that we are auto focusing on our uh text field in here so let's go inside the effects if the first text field and um and right after auto correcting here we're gonna say um autofocus true so when i press save in here and i go to the register screen you can see that the keyboard pops up automatically auto focusing on the first email field right there okay now we also have a little problem in here and that is that we haven't fixed our tests as you can see in here implement send password reset and mock auth provider and throw i can see there's a spelling error in the caption i'm going to fix that right away um like that i apologize for that um and that is here so let's go and fix our test so i want you to please go to us testing here and you'll see that we have an error here telling us in mock auth provider saying that we haven't implemented the last function that we just added to our off provider called send password reset so let's go in here and just ask it to oops ask it to create that missing override and what we're going to do for this exercise at the moment is just we're gonna leave this as it is on implemented error and i actually encourage you to go and do an implementation for the send password reset you may for instance do some mock and password reset do some future uh delayed a weight on it and change some states in your provider if you want to you're more welcome to do that so you could just take this as an exercise but we're just going to leave it like this for now but i highly encourage you to actually write some tests for this as well so we've now done quite a lot of work we've done quite a lot of reshuffling things around what we could do is just to have a look at the entire app and see how it kind of looks like so i'm gonna do a hot restart and we end up in here you can see our login screen works fine and if we try to log in with a user that doesn't exist in the application anymore so i could just type any password and say login and we get our updated screen that says cannot find a user then i can actually go and register that user the text field is autofocus that we fixed so foobar who barbaz register this user and we can see that we get this verify email we sent you an email verification we also have to clean this view up soon because i believe that this is not a part of this a particular chapter at the moment that we clean this up but we're gonna we're gonna clean it up soon um so the verification email should have been sent now so if i go to my mail application i'll just see if i can somehow bring it up so i can see that have i received any email from firebase yes and that email is available here i can bring it to the screen as you can see there is a link on it so i'm gonna tap this link and this will then verify my user if we then go to our firebase so if i say console firebase if we go to the console of our application now we should see that user generated here inside authentication so that user is right here and is verified user so we can just press the restart button and log in with that user so if i say foo bar bas log in and we see our dialog and there are no notes so i'm just going to create my first note in here and it's sitting there thinking and then i'm gonna say hello world all right that's my first note gonna go out let's go to the console again and to our application and have a look at our fire firestore database and make sure that that note was actually created and i can see that was actually created here hello world with that user id nvic if i go to authentication i can see nvic is actually and indeed that user so it seems to be working we have quite a bit of work still left we have worked with the with some margins we have worked with icons app name etc before we can submit it and these are things that we're going to take care of in the coming chapters but we've got we've come basically a good bit forward so we're almost there but not really really there so but no worries we're going to fix those soon and let me do some screen reshuffling in here and let's have a look at the committing of our work which is something that we usually do at the end of every chapter so i'm going to minimize scr cpy increase the size of visual studio code so you see my screen better let's go in here to the terminal and have a look at this shell in here and say git status and and yes we have a few files that are on track which are new which is our forgot password view which is new and password reset email sent dialog which is new and quite a lot of files that have been updated in here so let's just say git add all and also git commit step 27 all right hit status and we have to push our changes also so after we've done that let's also tag as is tradition at the end of every chapter we're going to tag this and push our tags and after doing that we can say git status as you can see there's nothing to commit in here and nothing to push again as a tradition at the end of every chapter we talk about what we need to discuss in the coming chapter so this is the exciting part at the moment we've been working a lot with the application code itself but we haven't really done anything to make it ready really for release the app store and the play store google play store and there are a lot of things that we have to do such as screenshots we have to prepare for each respective store and we also have to prepare the app icon the app name etc so lots of work to do and that's the kind of thing that we're going to take care of in the next chapter so i'll see you there hello and welcome to chapter 45 of the slatter course in previous chapters we've been talking quite a bit about our authentication and authentication block and then in the previous chapter we made our application a little bit more ready for releasing in the app store and google play store but we still have quite a bit left and these are like some of the final touches that we're gonna put on our application before we can release it in their respective app stores um so what we're gonna do specifically in this chapter as you can see in the caption at the bottom of the screen we're gonna take care of our app icons and the app name and i'm gonna take you through the process which works very well and has always worked for me so i'm going to show you how to grab free icons bring them into your application and also be able to kind of like automate that process you don't have to generate the icons by hand so to begin with we have to talk about what app icons are so so far we've been just kind of like running our application and just looking at what is inside the app itself we haven't really have we haven't had the time to actually look what's the application how the application is represented from the user's perspective on the operating system so if i bring up scr cpy in the middle of the screen and then i bring this application and the um all the apps up in this android phone for instance this you can see is our application right here so if i change the screen and a little bit here so you see better so you can see our notes application is right here and it has a default icon so every application on both android and ios and pretty much in every operating system has its own icon so flutter allows you or flutter provides a default icon for all the applications that you create with flutter create so you have a default icon that is displayed for your application but this is just a default flutter icon as i'm mentioning so we need to have our own icon that the operating system can display to the user in order to represent our application amongst all the other applications that are installed on that target operating system so that's for the icons and then what we have to talk about is what splash screens are so splash screen is this little screen that the operating system displays on the screen and as soon as you open an application so i'm wondering if there's any application for instance here that i can open up in order for us to see a splash screen so let's for instance go here to the clock application and as i saw here let me just bring it up again so if i kill the clock application by going here and then i go to the clock application again you can see that there is a black screen just displays instantaneously and then just disappears that is the splash screen and or in this case you could actually see it's the lack of its flat screen because there's no splash screen apparently for the clock application and let's go to calculator and this application opens up so fast it probably doesn't even have a splash screen but what essentially his flash screen is is a screen as its name indicate that gets displayed to the user just very fast while flutter is loading its binary to display to the to um the user so there are two stages for flutter to actually show a splash screen one is when the application binary is being loaded by the operating system and then there is another stage when the flutter engine is being loaded to be basically kicking off your applications process basically but i'm not going to go into too much details about that but just know that splashbearing is a screen that the operating system displays the user while it's loading the application so if for instance your application is being loaded or is being displayed for the first time on an android telephone version that has very old hardware because there are thousands and thousands of android devices out there then the operating system may actually take a lot of time in order to load your binary and that time it will and during that time it will display a splash screen so we're going to fix both the app icon and a splash screen soon so let's now talk about where you can actually find some icons so if you're a designer and if you're comfortable with figma or sketch for instance then you can go and design your own app icon you're more welcome to do that i can i feel free with figma i'm not a sketch user but i can design my like icons in figma but that's not what we're going to do in this chapter we're actually going to go to this website as i'm showing you here stockio.com and grab some free icons so if i minimize scrcpy here and bring up a safari window let's just say stock io.com you can't see that right now i'll bring it to the screen like that and you can see you can hear go to for instance icons and then there's a search functionality where you can search for the type of icons that you're interested in these icons are not really free sometimes they're actually they need to be paid for however you can also find um cheap or even free icons that you can use in your application but it's very important that you attribute the author work the way they ask you to do that and i'll talk about that soon so for our application we're actually going to grab this particular icon so it's called stock io we're going to go to free icon in here and say sticky note file icon okay so that's the icon we are going to use for our application and and you can go ahead and do the same thing i mean it's not that the app store is gonna like google play store and apps are not gonna set us like they're not gonna stop you from releasing your application just because your icon is the same icon as someone else's app so they're not gonna basically check that really unless your icon represents a very well-known app for instance if you add the facebook icon to your application then the people who are reviewing your application are going to know that immediately and recognize it and then they're going to flag it and perhaps reject your application but this is such a generic icon that i don't think anybody is going to basically have anything to say about it if someone else has used this already in one of the hundreds and thousands of applications that are available in in those respective stores so what we need to do here go and say free download as an svg so i just did that so let's go in here and have a look at that excuse me so i'm going to bring it up here and you can see it's an svg and that's been downloaded on my computer right now so i'm gonna um basically talk now a little bit about attribution so as you can see here in the information that is provided here on the screen i'm going to increase the size so you see it better it says free for personal and commercial use that's that means even if your application is free or paid for in this in this flutter course we're going to release our application as a free application of course but if even if it's for a commercial use you're allowed to use this icon but it says with attribution to stock io.com so what we should do if we're a good citizens of the internet land then when you basically upload your application to the app store and google play store as i'll show you later we will actually write a little sentence and attribute the um stock io.com website and even maybe say icon is provided by stockion.com and even place the entire url of that icon um inside our application description when we submit it to the respective app store so be very careful about this because there are actually artists that are creating these icons for you so even if you see that it's free you may be attempted to just say yeah i forget about i'm just gonna put it there i'm not gonna attribute the author but if you think about it it's just one line of text that you're going to write in your application description it's worth it because someone has actually sat there spent quite a lot of time designing this icon so it's just good karma to make sure that we follow these attributions apps that are provided in the website where you download your icons okay so now we have this svg icon so if i bring my finder here so we just have one file in here but as you'll soon see when we submit our application to app store and play store google play store we have to provide various icon sizes all right so and it's not that you have to provide the various icon sizes to the app store but when you build your application you actually have to provide these different icon sizes to the operating system for instance if the user is loading your application on a very old iphone without a retina display which i highly doubt now nowadays almost all ios devices have a retina display then that user with that phone that phone particularly cannot display very high resolution images so it needs to grab a particular app icon resolution however if you run your app for instance on an iphone 13 pro max then that device can actually display a high resolution image so using this svg file we have to create and slice it up so that we have various icon sizes to provide for various operating systems and device configurations so that's what we're going to do but we're not going to do that by hand we're going to use a tool in here called app icon dot co so let's go in app icon dot co and this is a great free tool that you can use and you can just basically drag your svg file in this target and it will generate your icons for you so let's go ahead and do that i'm going to drag this svg in here just like this all right and you can see that i can generate the icons for the destinations that i'm interested in our application doesn't support watch os at the moment and we're not a mac os application so at the moment we're just saying iphone and ipad and for android okay so let's just generate these icons and if i go in here i can see that there was a zip file generated in here so let's just unzip this file and have a look at it and you see that there's a folder called app icons so it has android app store assets etc in here okay so now that we have these icons generated here as a caption indicates we have to add them to our application so how do we do that do we go ahead and like add these by hand no but there is actually better way of doing this so i'll explain it to you right now there is a package called flutter launcher icons that can take care of this for you so instead of you having to place these icons manually inside your application binary or inside your application source code for instance visual studio code or android studio it can do that for you so let's go to pub dev i'm getting rid of this dialog here as well and let's search for flutter launcher icons okay and we found it right here and you can see that it is provided by the flutter community right there and there is information on how you should actually configure this and we'll get there soon so uh but what we first need to do uh is to bring this into our application so this uh plugin so let's go to installing in here and you'll see here that it says dart pub and with flutter we want to do this basically father pub at flutter launcher icons okay so let's go ahead in our application so i'm going to bring our application in here and let's go to terminal so let me bring this up a little bit and let's just paste that command in here um boof all right so that is just going to add flutter launcher icons to our application and so that's the adding of it so if you go to pop spec yaml now and have a look at our yaml file you can see that there's this flutter launcher icons added right here okay then what we need to do is to create some sort of a configuration file for this plugin and to understand how it should generate our icons for us you can see if we go back in here you can see that there's some information about that if you read the readme file it actually asks you actually to generate a file called flutter launcher icons yaml and that's exactly what we're going to do in here so let's go to the root folder of our application so if i collapse every folder in here so make sure that you're in the root folder of your application and then i'm just gonna say new file and let's just add flutter launcher icons okay and in here they basically say add this assets icon etc etc so let me just bring this here copy this information as it is stated there and place it there but we also have to add a new um and basically key in here called remove alpha ios and we have to set this to true and this is a key that i don't know if it's actually documented so let's have a look at the documentation in here let's see version scores change log installing it's not really documented unfortunately but there may be inside the git repository for this application like there may be some good documentation to be honest with you change log examples um flavors could there be anything in there production no unfortunately but i will just explain what this key basically does what it does is an ios as an operating system it doesn't allow alpha channel transparency channel on its icons on its app icons so what you need to do is to get rid of that so when we generate our icons we're going to tell this plugin that hey when you're generating the ios icons remove the alpha channel and for you designers out there you already know what alpha channel is okay so it's just a transparency layer all right so what we need to do now is to grab our icon the downloaded icon and place it inside assets icon icon.png okay so as you can see in here let's see if you have an assets folder and we don't so let's go ahead and say new file oops a new folder and i'm going to say assets and then we're gonna call it icon okay just like that and let's go then and bring that app store png file that is right here and just place it inside the folder that we just created so it's a huge file okay and that's okay so now that we've done that and you'll be wondering okay where why is it under assets icon and that's because in this launcher configuration we said that that icon should be there you see icon png so what we need to do now is just to rename this file to icon.png just to make sure that this package can find it under assets icon icon ph png as it's specified here okay so in order to then generate your icons you just have to run this for this command right here so i'm gonna i'm gonna go to terminal let's see uh terminal is actually right here it's ginormous um let's go here terminals and i'm then going to clean the terminal get rid of the left hand side bar i'm going to say flutter pump run flutter launcher icons and main just like that that is going to basically do its job have a look at um the configuration and then it's going to generate our icons for us so in order to test this we actually need to make a clean build and this is a little bit of a pain in the neck and that's completely okay it's just because we change something dramatic in our application and then we need to just make sure that we stop the running of our application so i can see now this particular application at the moment isn't running in scrcpy so that's really good as you can note here this is the icon of our application right now without us having launched it again so let's just do as the caption indicates we're gonna do flutter clean and after cleaning is done we're just going to say flutter pop get in order to grab all our dependencies again and i can see that you can't actually see what i typed there but that's what i typed flutter pup get as you can see here and it grabbed all the dependencies again and what i'm going to do is just going to go to main dart file in here and just run the application but before doing that i'm just going to also make sure that flutter select device has selected the correct device which is my android app and which is my android phone and just gonna say run without debugging it could actually help if you removed your application as well so just to make sure that that application is completely deleted from the phone so it's completely gone now and really all we have to do is just right now wait for this gradle task to complete its work so i'm just gonna let it do its work and um let's just wait for it all right now you can see that our application is running on uh scr cpy which is an actual real phone in here so if i now go back here and bring up all the apps installed on this device you can see we have this application running right there my notes and it has this little icon here and this is another application that i've had from before so i can just uninstall that safely and we just go to our application in here you can see it is as we left it last time but the important thing is that there is a new icon basically provided here so that's really good now we've tested that on android so the testing of android is actually done so you don't need this caption at the bottom of the screen i should have brought up brought it up a little bit earlier and what we need to do is just to run our application on ios as well so i'm going to stop the the execution of the application on android and i'm just going to say flutter select device and iphone 13 pro which is a simulator and then i'm just gonna say run and this is also gonna perhaps take some time because usually i run my applications on the android telephone as you've seen with scrcpy i usually don't run with an ios simulator or a device when i'm developing with flutter and but it is always good practice to do that so now it's doing the xcode build and let's just wait for it to finish okay and now we can see that our application is also running on ios so what we can do in here is just to send the app to the background and then you can see that we have our my notes application right here and the icon that we basically created for our app so that seems to be working as well what we need to talk about now is our app name and as you can see in the caption at the bottom of the screen since we need to update the app name it's not so nice as it is now and right now it's just saying my notes with a lowercase and and capital m and all in one word so it's not as it should be so let's go ahead and fix this and the way to do that is that you have to do it in two places one for ios and one for android so we're going to take care of ios first so in visual studio code i'm going to jump into a file called info key list and this is the info p list is like basically an ios applications and kind of configuration place which you can configure a few things for application like permissions etc and if you go to this uh file ios runner slash info p list so let's go in there and then there is a key in here called core foundation bundle name so let's see if you can find a bundle name cf bundle name at the moment it says my notes in here so we need to fix this just to call it basically my notes like this okay and let's see if there's any other place in here we can also see that there is a bundle display name which we may also have to fix so let's just call it my this and to be honest with you we don't maybe actually have to change the bundle name i would say maybe changing the bundle name is not so good so let's not do the bundle name actually i'm going to change the caption and just call it changing the bundle display name because i would say a bundle name and bundle display name are two completely different things the bundle name is like the binary name of the application and the bundled display name is what the user sees on the screen so let's not do the bundle name and let's just change the bundle display name in here and just call it my notes okay so after doing that we could try to stop the application in here and then run it again um it may take effect it depends kind of on how flutter is gonna trigger these changes with xcode build and how xcode build is going to interpret our changes sometimes it might actually be necessary for you to do another clean and then run the application again on that target platform so that's just a bit unfortunate when you change like huge changes when you make you changes to the applications structure and i could see now that my notes was actually taking the fed effect right now so we don't have to do any flutter clean so that's really good then what we need to do also is to update the app name on android and we do that by going to android app src main and we could just do that right now so let's go to android manifest xml and you can see here is android app src main i'm going to go in there and then i'm going to find this key in here android label and just change it to my notes all right so let's just do that and then i'm going to go here just to a flutter select device run it on my android phone then i'm just going to stop the ios execution and just go to run run without debugging so that you can try to run the application on this android phone so if everything works as expected then we should have our mynotes application right here with the correct uh icon and then we should also have the correct label alright so let's just send this to the background let's go in here and have a look at our application you can see now it says my notes the right icon and also um yeah the application is running as it should and if you go back to our ios application then we can see the name is also correct and the right icon so we could actually say that we've already tested things on ios they seem to be working so if i bring up the simulator the app is working as it should and we don't have any crashes the icon is correct and the label is correct and on android if we bring up scrcpy again you can see that the icon is correct and also the name of the application is correct so we've done what we said that we're going to do in this chapter we talked about icons and we also talked about what splash screens are in preparation for the next chapter and it's usually the um what we do in the and at the end of every chapter we talk about what we need to discuss in the chapter that's coming so what we need to do in the chapter that is coming is to prepare ourselves for creating splash screens you now know what splash screens are but in the next chapter we're gonna go and create them and we're gonna add them to our application so grab some refreshments if you want to do and i'll see you in the next chapter hello and welcome to chapter 46 of the slaughter course um if you follow the chapters up to this point chronologically you'll know that we've done a lot of preparation and we're actually about to start preparing our app to be submitted to the app store and google play store but before doing that now that we fixed our icons and our application name for both android and ios we need to fix something called a splash screen so and we talked briefly about splash screens and what they actually mean in the mobile world for instance in both android os and ios and ipad os for that matter but for those of you who missed the previous chapter a splash screen is a screen that is displayed to the user when they open your application from a cold boots basically meaning that your application hasn't been running for instance in the background in that operating system and while the application binary is being loaded to the screen and the experience is being loaded to the screen um then the host operating system in this case android and ios will have to display something to the user while they're waiting for the experience to be loaded so in native applications for instance if you're creating a native application with um coupling for ios sorry kotlin for android and swift or swift ui for ios then um in that case there is there is only one stage of loading for application in that you submit your binary to apple and then or um to google play store and then the host operating system just loads your binary and then that um your main user interface is displayed to the user so it's just one stage in flutter however there are two stages of loading your application one is the your application binary in itself being loaded and the second stage is for the flutter experience to actually be loaded inside your application since flutter is its own sdk basically so what we're going to do is we're going to create a splash screen that gets displayed to the user while our application binary is being presented to the user so let's have a little look at a the official documentation for splash screens and i'm going to bring the screen up here and increase the size perhaps a little bit so like this so you see here as it is explaining here first and you have your android for instance operating system in here and you tap on your application icon and then it goes through a series of steps in order to land on your application's um main interface and here there's a great documentation basically for splash screens which i recommend everybody who wants to submit their application to ios app store and google play so to read this thoroughly because there's great pieces of information here even if you are just following for instance my advice in this chapter but it is still a good practice to go ahead and read about this so um before we actually go and start designing our splash screen i also have to mention something that [Applause] this chapter is quite i mean you need in order for you to be able to go through the chapter you will unfortunately need to have a macintosh so because we're actually going to play a little bit with our um ios splash screen and for that you need to have xcode but i'll talk soon about that as you'll see so how do we go about creating a splash screen so i mean there are so many different ways of doing this and if if you're a developer from before you probably are not so comfortable you're not this kind of like a unicorn developer you might not be a so-called unicorn developer as a developer who's also comfortable with designing or you might you might only be a designer and you've started this course and you've come to this point so you may actually be comfortable with a tool like figma so um depending on your background you may or may not be comfortable with designing so i've basically taken the liberty of using a design tool a free design tool called figma and for this chapter which you can access freely with for instance a google account or an apple apple id or you could just create a normal free account on figma.com but i don't make the assumption that you know anything about designing and for that what we're going to do is we're going to create a very very very simple splash screen in figma assuming that the person is watching this course has no information about figma or designing previously okay so let's have a look um now that we talked about figma let's have a look at storyboard on ios so um what we can do in here is to bring our application to the screen so i'll bring up our app in here increase the size a little bit so you see it better and what we can do is to bring up terminal in here so get rid of a little bit of distraction in here so let's see so if you say good status we have a lot of stuff that we've done but we haven't committed them so that's fine let those be there we're going to commit them soon okay so in your application what i need you to do is to have a look at your ios application so there is something in the ios application generated by the flutter template when we created our our template from the absolute beginning of this course and there is a file a specific file called a launch i believe it's called launch screen dot storyboard if you're not comfortable with ios development like native ios development from before i can just explain you that a storyboard file is a file that apple designated for um developers to be able to visually design their application and then write the code for it later and apple's decided that for specifically the launch screen for instance that gets displayed to the user there should be a a dedicated um storyboard file for that so we're gonna go ahead and launch xcode on this macintosh in order to manipulate that storyboard file but before we do that i'm just going to go ahead and open the root folder of our application then i'm going to go and let me also change the screen layout a little bit so you see things better then inside this ios folder so in the root folder of your application go to ios and then you can see two files in here runner xcode proj and runner xc workspace and dependent on your settings on your macintosh you may or may not be able to see the extensions of these files i i've i've done so in my macintosh that i can always see file extensions because it's important for me so if you're not seeing the extensions you just have to trust on the icon so one of these files has this bluish icon which says project here and the other one is a workspace i need you to basically double click on this workspace in order to open it okay so let's go ahead and open this workspace inside xcode and let's then go have a look at this launch screen inside this runner folder so if i collapse everything inside you will see that you have your runner and which is the flutter templates created workspace inside there we have another runner and in that runner folder then you'll have this launch screen so we can then have a look at this launch screen and see how it is created and you can literally click in here in order to expand the contents of this view controller to have a look at the internals of this launch screen and a good trick is if you want to expand you can see here you have to expand this and then you have to expand this and expand this if you don't want to expand one step at a time you can always hold down the option key or the alt key and then click on this little arrow and that expands the entire chain for you and if you want to collapse the entire chain you can press down alt and then click and then collapses the entire change so let's let's expand the entire chain and then in here you'll see that there is a view and then a launch image image view which at the moment is pointing to a file called launch image which doesn't exist because if you go to our assets in here you'll see that launch image is just empty at the moment okay so there is no launch image meaning there is no splash screen okay so we're gonna manipulate this file a little bit as you'll soon see so let me just keep xcode running okay so that was the basics of that launch screen storyboard and as you see at the caption on on the caption at the bottom of the screen this is an unfortunate unfortunate thing that um that apple isn't as open in my eyes at least as many other companies like microsoft and google in that if you want to for instance do native ios development and have xcode in order to open your project and run your project for instance then you'll have to have a macintosh because xcode isn't available on other platforms and it's very unfortunate i mean it's it's nothing to really be proud of i would say i'm a native ios developer and i'm actually ashamed of the fact that xcode the tool that i use on a daily basis is only available on a macintosh because i might personally for instance like to write my code ios code on ubuntu or fedora or some of you may actually prefer windows but let's not go there let's just say that you'll unfortunately need macintosh in order to be able to manipulate that um launch screen as storyboard file and for those of you who don't have a macintosh you'll need to contact perhaps somebody in your network who does have access to a macintosh and ask them to manipulate the storyboard file for you and add your icons as you'll soon see how and then send that storyboard file back to you so that's an unfortunate problem um so what we need to do is to actually get to the roots of what we need to work on in this chapter and that is creating a splash screen okay so as i mentioned in the beginning of this chapter i'm gonna rely on a free tool called figma so let's go ahead let me see if i can do some re reshuffling on this screen and close a tab in here i'm gonna bring up my browser gonna minimize our application and bring up my browser right here so i need you to please visit a website called figma.com and in figma.com then you will have the ability to create your design files all right so i'm not gonna show you actually how to register for figma because that is very easy so you can just perhaps if i for instance go to and bring up a completely new tab in here and say figma.com where i'm not logged in you can just say sign up and as you'll soon see here you can continue with google or use an email address of your choice in order to sign up for figma and as i mentioned figma is free until to a certain point and you can you can for instance um work with your uh normal design files in figma without having to think about actually paying for a subscription but if you want to do advanced work for instance if you want to do a lot of sharing of your work with other team members etc then you will need to pay for figma so after you've registered your account in figma what i need you to do please is just to go and click on new design file okay so i'm going to increase the size in here and just say new design file all right so it's created a new design file here for us and as you'll see as you'll see in the bottom of the screen in here um i wonder if i actually have to bring my face to the right because i'm blocked by that so i hadn't noticed that so um so what you'll need to do is to create a container here on figma maybe this is a better screen um yeah set up maybe this is better okay so what we need to do in here is to create a container that is at 1284 by 2778 and i didn't i didn't like make up this number this is the size of a screen for an iphone 13 pro max so if you're not a designer you may not notice but when you're designing things you always have to create like your design so that it it scales to various sizes this was not a problem back in 2007 or 2008 when we only had one iphone and just a handful of android devices but nowadays you have to kind of like create a template in for instance figma and then ensure that it is scalable for different sizes but we're not going to focus on that right now all we're going to do is just to create one splash screen and then inside our ios app and android app we're just going to make sure that it scales okay so let's just target one device at the moment and in here i need you to go in here and actually here sorry about that and create a rectangle after creating a rectangle we're going to go in here and set the width to what i've specified down there 18284 i can see my keyboard and the height is going to be 2778 okay so it's a huge rectangle as you can see here okay so that's our rectangle and what we need to do is to kind of give this a background color now as you've seen so far and if you follow the chapters chronologically for this course you'll know that i basically use a very very soft theme in visual studio code for uh coding and i absolutely love this it's the preference you may like a light team i like a dark team such as tokyo night and tokyo night is a visual studio code theme that is open source and you can actually grab its colors from github so what i'm going to do in here is just to make sure that the background color of our splash screens actually painted with that color okay so let's go and search for tokyo night in github and you'll end up in this website github.com and kia tokyo night vs code theme so if you don't have this link and if you couldn't be bothered writing this name you could just google and so i'm just gonna go to google and say tokyo night theme okay and you'll end up with the github link so you can just click on it all right so i'm gonna go down here in this um theme and i'm going to grab this beautiful editor background storm color from here okay um actually either we could use storm or night i'm gonna choose storm and just see how it looks like so grab this code please the rgb code for uh tokyo knight and let's go to figma into our rectangle and just paste it in fill so that created a nice little background color for us okay so we could just live with this at the moment then what we need to do is i like to basically create some sort of a gradient in this background color so it's not so bland as it is right now so what i'm gonna do is just to go to effects in here and then say that we have actually no not effects it's probably in fill let's go and fill press the plus button and in here just click on this little uh space right there and let's just say that um you know what actually i would really like to change the screen layout a little bit so you see my figma screen better so i'm gonna hide this caption and let's see and see if i can change the caption length like this so that it is smaller and hence i can change the screen layout with my screen with my face still visible so i think this is a little bit better okay after doing this fill so we added a fill effect in here using this plus icon and go and tap on this um little icon next to fill you see here clicking on it you can then say that you want for instance a linear should we create a radial maybe or a linear gradient let's see let's create a linear gradient okay then this as you can see is a gradient that at the moment is going from black to transparent with zero percent in here so let's make this black point as well transparent like this zero and we're gonna in both these cases set the background color as the starting point and the ending point so click on the starting point change this color to our um tokenite background color and here as well so that's that okay then in the middle somewhere we're gonna create a point and give it a hundred percent uh transparency and let's see how it looks like so in here can we not have three points yeah figma just went a little bit ballistic on us but that's okay so in here we have that color in here we have that color so so the start and the end have to be transparent with that color that we've chosen and let's go in in the middle and just kind of change the color to red and you can see that it gets created here without a problem and then what we're going to do for the middle we're going to go and create grab this particular color here as you can see it's kind of like a light very soft light blue starts with 7d so it's 7dcff and i'm going to go back to the figma design and in here change the middle color to that just like this okay so it kind of creates a nice little effect for us in the middle kind of a nice gradient okay so after doing that let's go to our downloads and grab our icon so i'm going to go here to downloads and if you remember we had this sticky note svg file and figma is great with stuff like this so let's just grab svg right in the middle okay and that's our sticky note right here okay so let's see what we can actually do should we use the svg or should we use maybe our app icons it's probably better to use actually the app icon so revert this change please so let's not use this svg let's go to our app icons that we extracted in the previous chapter and let's grab a rasterize png which is this app store icon and bring it right here okay so it actually is a nice size i'm going to use these built-in layout guides in figma as you can see it tells me where the center is so i'm just going to place our icon right there and as you can see it actually blends really well with that background linear gradient that we created so it's a it's a subtle effect so you can see that the linear gradient is a little bit visible and if you disable that linear gradient with this icon it's it's very bland so without that linear gradient it's our splash screen doesn't look so well so you can also play a little bit with the transparency of the entire thing like 100 and i feel like um this is just crazy so maybe 20 was actually pretty good i don't know where i went so here let's go back here and say 20 okay as it was so now we have a really good um base for our splash screen so what we need to do now in order to download this splash screen you need to select those two layers so on my macintosh i'm just going to hold down the shift key and click on this icon for instance and then click on the next one in order to select both where i think you could actually no you can't select like that so you need to basically hold down the shift key and select both layers then press command g on a macintosh or ctrl g on linux and windows in order to group these two layers together okay so now it's a group and i'm just going to call it splash screens just like that it doesn't have to be called like that splash screen but i just call it so okay so what we need to do is to grab this splash screen in three flavors so normal like um in normal ios development you have to support three different resolutions for your assets usually some developers are not as bothered with supporting older devices so they only support for instance the resolution of 2x and 3x and if this doesn't make sense to you i will just explain what this actually means um modern devices on ios at least they're called at their screen and they're called retina devices and it's just a term created by apple um many many years back and where they said basically they doubled the amount of pixels that a device can display on the screen but they held the aspect ratio as it was so if in a little square in an old device the device could display four pixels then the new devices could display eight pixels so they doubled the amount of pixels per square feet i don't know how you want to say it and they call it retina and then they added they said every every developer needs to provide an image for the old devices and we call it 1x as in scale to 1 and the new devices will have 2x then newer iphone devices came out they had more modern retina displays and even more pixels packed into the same space so they said now those devices are able to display eight times more pixels than the original ones so it's basically gonna be um one x two x and three x so um i think it's eight times more is that i don't know so it's 1x2x and 3x that we have to support so let's go in here um let me see if i can shuffle things around so you see better um maybe like this so let's go in here in figma at the bottom of the screen you see this export button so i'm going to press that export so i'm going to press that export button actually three times as you can see in here so we have the first one is a png make sure that they're all png files and the first one has no suffix second one has two x and the third one has three x that's exactly what we need okay so after doing that what we're gonna do is to say export splash screen just like that and that's gonna do its processing so it may actually take some time depending on our internet connection as well and then we downloaded this zip file so our work in this file is basically done and this is the contents of that zip file as you can see splash screen png and they're all the same but their sizes are quite different you can see the first one is 604 kilobytes the second one is 1.4 megabytes and the third one is 2.5 megabytes okay so after doing that let's now remove safari or your web browser from from the screen and we need to basically go into our source code now so i'm going to keep this window here do some reshuffling on the screen and then i'm gonna bring our let's see i'm gonna bring our uh application to the to the screen like this okay and actually we don't need the application sorry about that we kind of need xcode in here so let me bring up xcode but let's bring xcode to the screen and what we need now is to go to our assets in here run our assets and we have our launch image right there so what we need to do is to grab these images one at a time and bring them in here okay so and they can be called splash screen that's not a problem xcode will do the mapping for us so as long as this thing in here is called launch image then we're good to go so as a caption any case we're now going to go and bring these images in here so we have three images you can see in here and we have three placeholders in here that we have to drag and drop our images into so let's begin by splash screen png and bring it to 1x let's bring our splash screen 2x into 2x and 3x into 3x okay and just like that so that part is now done but we're not really done designing this splash screen as such for the ios app so let's go to the launch screen storyboard file in here as you'll see it doesn't look so well so we need to find this launch image that is displayed in here and you can see at the moment its constraints are like very very wrong so it just thinks that if you go into this tab it thinks that this image is one two eight four by two seven seven eight but we don't want that okay we want this image to be as big as the screen but we also want it to fix the aspect ratio of the image so that it always fills the entire contents of the screen even if that means the image goes a little bit outside the outside the boundaries of the screen okay so that the launch screen looks great on all ios devices so what you need to do here is just a little bit of a work on ios side so you need to go in and select your launch image in this tab in here which is your dimensions the size inspector as as it is called in xcode go and say that the x is zero and y is also zero so that kind of like make sure that your image starts right there then let's just zoom out a little bit and go manually and drag this a little bit so that it fits the screen so i'm going to drag this point let's see if i can do that with my trackpad or maybe i should use my mouse and it's it's like playing a little bit with me just because this launch image at the moment has some constraints so let's go and actually remove these constraints so i'm going to remove this horizontal constraint by pressing the backspace button on it or if you're on windows and linux you have to press the delete button on your keyboard so now i've removed those constraints so i should be able to freely size this hopefully let's see and it's not letting me size this but that's okay so what i'm going to do is i'm going to have a look at this view and see its size i can see that view is 896 then i'm gonna go to my launch image and say okay your height is also 896. so that's going to ensure that the height of my launch image is the exact same height as the view then i'm going to have a look at the views with is four one four and i'm gonna go to the launch image and say you're also four four one four okay so now the image container actually looks good however this launch image it now has hard-coded values hard-coded width and hard-coded height it's x and y and y are quite fine but what we need to do is to create some constraints for it and constraints are literally i mean we're not going to go into native ios development at this moment so you need to kind of have some knowledge about this yourself and if you don't i'm just going to tell you just quickly how we create these constraints so what we need to do is to click on our launch image and then drag and hold down the control button on your keyboard okay so click hold down control and drag from launch image into the view like that then this menu appears on the screen and then hold down the shift key on your computer on your macintosh and say you want an equal width equal height and also you want to see leading space and you want to say what else do we want yeah that's fine for now i would say i mean ideally what we want is for this screen to be in the center as well so maybe we could just say center horizontal and center vertical so check these four items as you're holding down the shift button and then you can let go of the shift button and then just click here anywhere on the screen to dismiss of that so now you can see xcode is also happy with the constraints that we created then what we need to do is just to tell this image to scale according to its width and height so let's go into this tab which is called let's see what this tab is actually called attribute inspector and inside this scaling here actually it's not scale really i believe it should be content mode in here and let's just say it is aspect fit okay so it keeps the aspect ratio of the original image but it also ensures that it's like yeah it's fitting on the screen for now okay so let's leave it like this all right so let's then go ahead and actually see if this looks okay so what we could do is to write in xcode let's just say yeah let's run on ios 13 pro which i believe is the simulator and that i have already in here and from from xcode itself we can press the run button to have a look at how this actually looks like and while this build process is going you can also go to your simulator here and say file and open simulator and i'm just going to choose another simulator as well such as iphone 8 plus okay it is just good idea usually to test your splash screen and the functionality of your application on as many devices and simulator as you can i mean i actually prefer to test on real devices but right now it is quite difficult for me to bring so many test devices on the screen so i'm just going to use a simulator to test the splash screen okay so now what we're doing is just to compile our application for iphone 13 pro which is a simulator we've been using so far when it came to for instance um testing our application so let's move this to the background because this is not really our application this is our application so let's bring it here and let's just give some time to xcode to do the work that it needs in order to build our application for this simulator and also install it and run it so that we can have a look a little bit at the splash screen so i'm just going to be waiting until that process is done all right now our application is running on a simulator called iphone 13 pro so what we need to do is to actually kill the running of the application because after the application is launched we're not going to see the launch screen even if you for instance send the application to the background with command shift h that sends the application to home and bring it back up there is no launch screen remember launch screen for an application is only displayed when the application is completely dead and it's cold booting so in order to send in order to basically kill the application what you could do is either press the stop button here on xcode which basically kills the debug process and and also kills the application so now you can actually click on the application in your home screen and bring it to the foreground and as you saw that was the little splash screen that we saw on the screen so i'm gonna kill the app and bring it back up again and that's our splash screen so seems to be actually looking fine on iphone 13 pro let's now change the target in here and change it to our iphone 8 plus which is the other simulator that i brought up here and the reasoning for that is that iphone 8 plus is still a major player in the market a lot of people have iphone 8 plus and the screen is fabulous it is a great phone that people are still using so and the huge difference between iphone 8 plus and iphone 13 pro is that iphone 8 plus has no notch so it doesn't have um the notch that you can see in here on an iphone 13 pro so and it has a home button so that's a little bit of a thing that we have to think about that you need to test your application on multiple devices and now i'm going to kill the application oops i don't actually know what i did so let's go in here and i'm going to kill the debug process on iphone 8 plus as well and run it again and let me just delete this old app from here so we so we don't get confused and if you run the application did you just see it momentarily that the application that the splash screen doesn't look so good it's not doing so well so if i run it again with do you see the spacing on the right and left if you pause the video you will see it that is because we have a little bit of problem with our aspect ratio in here because you remember in this launch emit launch image we said aspect fit what we need to do is just to say aspect fill and aspect fill what it does it tries to keep it it doesn't try it keeps the aspect ratio but it always makes sure that the image is that is at least as big as its container so having done that let's run the application again on iphone 8 plus with that change in mind and let's see how the application looks like now it looked a lot better so there was no empty space to the right and left i'm gonna kill the application like this send it up bring it up and let's see oh it's because my debug debug process i just killed my debug process so let's kill it again like this let's see if i c if i can manage to do that kill the application and open it and now i can see that this splash screen is actually looking good on iphone 8 plus as well great now that things are working fine on ios we need to focus on android so let me bring up the caption for the next section that we're going to talk about we're going to talk about android slash screens here i'll also try to open this url so let me bring it here so you'll see that there is official documentation about creating splash screens for android as well on developerandroid.com guide topics ui splash slash um splash dash screen and um here there is a lot of information that you can have a look at and like even animations as you can see in here what splash screens mean to android applications and that you can even animate them etc etc so i suggest that you actually read the documentation for splash screens on android to get a better understanding of the differences between ios splash screens and android splash screens it's always good to know i like the underlying implementation and how it actually works under the hood if you're a flutter developer you don't necessarily have to only focus on flutter but you since you're deploying your application compatible with for instance mac os linux windows and android it's always good to know in my opinion how it works under the hood so if you want to have a look at this please go ahead and read the documentation on how it works and now let's go to this a little beauty of a link which is on stack overflow which which is one of my favorite websites to find um solutions that i can't even think of the answers to sorry the problems that i can't find the answers to so let's go ahead and have a look at this url in here which will explain to you the different resolutions that we have to provide for our splash screen for an android device and you saw it from our figma design in here it's gonna load now excuse me um so here you saw that when we exported our oh this sticky note shouldn't be there i don't know why it was added there so i'm just going to remove it and i hope that we actually didn't create our splash screen with that in we could double check that by bringing up xcode and have it looking have a look at our assets and just have a look at these images showing finder excuse me i'm going to bring it up and i can see that little sticky note wasn't in our splash screen so that's really good it was just probably a mistake from my side so that's great so as you saw for ios we exported these assets in here three two one x with these suffixes so two x four two x three x for three x and nothing for the normal um splash screen on one x devices but on android there's a lot more that we have to export so i'll open that url in here that you can you'll also see and you'll see that these are the various um resolutions that we have to export for our splice screen on android we're not in our application supporting ldb ldpi in here so we'll we're going to go and export mdpi hdpi xhdpi and etc etc so let's go ahead now in your figma design right there select your splash screen from the left hand side and go go ahead please and remove all these exports that we've created earlier okay so what we need to do now is to make sure that we're conforming to these sizes for mdpi for instance and we're going to basically select the splash screen and say export and let's in here see that okay these are the sizes so 1x let's just say we don't want any suffix and i've already prepared something like that before so let me just show you how it should look like and i'm going to select this splash here and you can see this is pretty much how you should create it so one x and we say mdpi as it was displayed in here mdpi you see and then we say one and a half x is hdpi and xhdpi etc etc okay so let's go ahead and do something similar in our splash screen in here so one x and as you could as you could see in the one that i preferred here one x was mdpi so let's go ahead and say a suffix is mdpi like that i'll create another export in here and we're in this case we need hdpi which is one and a half x so let's select this and say one and a half x and we say hdpi like that and then we go for the next one which is xhdpi so let's go and press the plus button in here and say 2x is a x hdpi and then we go to the next level which is xxhdpi so let's press the plus button and say uh and this needs to be x x hdpi okay so we're gonna say xx hdpi and last but not least we have triplex hdpi which is four x the resolution so let's say xxx a plus button triplex hdpi and in here this should be 4x okay so now oops i didn't want to create this drop shadow so that's how yours should also look like with all these uh various resolutions in here okay so now what i need you to do please is just to go ahead so make sure that your slash screen is selected on the left hand side and then just go and export all of these so let's just press the export button so that's going to take its time and calculate basically all these different resolutions prepare the pngs for us and it's going to pack them into beautiful zip file and then it's going to download that packed file for us so depending on your connection speed this could take some time and the result i can see is an untitled 2 zip file uh of about 10 megabytes so there we go so let me double click on this file in order to unpack it and i'm going to open the folder here for you so you can also see as you can see splash screen it's all there so they're all looking very similar to each other but they have very different sizes as you can see though so the xxx hdpi has the size of almost four megabytes whereas the mdpi is only 600 kilobytes so now we got our images perfect so what we need to do is um we're going to basically call them splash screens and then place them inside various um mipmaps folder in our android application so let me bring up visual studio code in here let me see where i've placed my visual studio code right there okay and if you then ex go into exploration a little bit here you can see we have an ios folder so let me just make the size a little bit bigger excuse me and we have an android folder in here so if you go to android and then app src main and then res and you'll see that you have these mipmap folders hdpi mdpi and all those one two three four five folders that we need for our five assets in here okay so let's go ahead and actually name this file in here and let me close this little folder that i have at the bottom of the screen as well so okay so um we start with mdpi in here let's just call it splash okay slash png and i'm just gonna go to this mdpi folder here and i can see i have a launcher icon an ic launcher so let's just drag this into mip map mdpi if i can and mid map mdpi there it is so the mdp i want is done now i'm going to delete it from here so now we have hdpi then i'm going to call it splash again remember it's hdpi so i'm going to drag and drop it into the hdpi folder so it's called png there as well then i'm going to delete it from here then we have the xhdpi so i'm going to call it splash again and remember xhdpi so let's go and drag it there great then delete it from here then we have xxhdpi so call it splash again and bring it into xx folder in here and i can see it's right there splash okay and last but not least we have the triple x hdpi and we're going to call it slash again and then let's go in here and bring it right there great so now you should actually see one two three four and five images that we have exported and placed inside our android folder so then i can delete the last one safely so now that we've done that we need to actually tell our android application to use those splash screens so what we need to do is to look for android window background inside our application i'm going to close all these open tabs and i'm going to search for android window background just like that okay so you'll find four of them but only two of them are actually interesting for us so what we need to do is actually i'm going to go to my styles as well here so as you can see here is using a drawable but we're not using a drawable a drawable is something that for instance if you look for launch background let's go in here you see these um fine launch background actually is there a drawable called launch oh we don't have it right now okay anyways so i'm gonna search for um android window background as it was our mission so let's go in here and find that window background and here as you can see it says drawable launch background and this file is android app src main res values styles xml so that's the first one okay that's this drawable so i need you in here to change this to mipmap and in here just say splash which is the name of our file that we created okay so that's the first um occurrence of this android window background and then we're going to go in here as well which is in android app src main res values knight styles xml and call this mipmap like that and in here we also say splash perfect so we've changed those so what we need to do now is to actually test our changes on android as well so i'm going to close all those tabs as you saw and let's just go to main dart file just to have a dart file open and then i'm going to stop the running of this application because i don't really know i think it's actually running the application on um the iphone simulator and then i'm going to say command shift p on a macintosh or ctrl shift p in windows and linux if you're on visual studio code and then say flutter select device as you can see in here and then i'm going to choose my android phone okay and as you know from the previous chapters i actually prefer to run my applications real phones and then run and then run without debugging and this is gonna basically kick start our gradle build processing here and while that is ongoing i'll go and bring um scr cpy to the screen so here it is and i can see nothing actually what happened to our build i think our build somehow crashed so let's go and build again and see what happens debug console and okay i can see it says there is a problem and let's see another expected caller reference bot got raw string mid map splash okay so let's have a look at what we actually did with this mid map splash i can see i've actually written incorrectly i've written me map so that could that could explain it it's a mid-map so if you've done the same mistake as me in one place please just correct this so it's mipmap all right so fine okay fair enough and let's now try to run the application again and see if it can compile this time so it says it got a raw string again and it's now did i really type it in correctly did i write mimi map this is unbelievable um if i've actually done that so so no i i think i've actually written it in two places incorrectly so map all right it would be very comical if i made a mistake again while trying to fix my previous mistakes so let's see now if the android build is gonna go through successfully so i'll just wait here until that task is done okay it's built successfully i was just gonna go grab some coffee so and it's connecting now so that actually went really fast i would say gradle builds in here are surprisingly fast when running with flutter for instance compared to the ios xcode build system so i'm going to bring up scrcpy in here and i can see the application running without a problem but we didn't actually see our splash screen so what i'm going to do is i'm going to stop the processing here which kills the application and then i'm gonna find our application here and then open it and then i can see our beautiful splash screen on the screen when the application starts so that's also working as expected no problems at all and remember we've done quite a lot of work now we've done like icons from the previous chapters and we've also worked on our splash screen so there's lots that we've done but we haven't really committed any of these because the work wasn't complete however now that we have um both icons and splash screens on both ios and android i think it's time that we do as we usually do at the end of every chapter is to commit our work and make sure that we're not going to lose it so i'm going to do some reshuffling on the screen right here and i'm going to increase the size here as well so i'm going to go to terminal then like this and let's then have a look at the status and you can see that we've done a lot of work so there are many files that have been changed as you can see in here modified modified a tremendous amount of work so let's just say get at all and then let's commit all this work as is it step 28 yes step 28 okay so if you look at our logs so we have step 27 and then we have step 28 as well so i'm gonna push all these changes and this push is actually quite a big push because we have a lot of resources that we're pushing to github so or wherever you're hosting your git repository it could be bitbucket or somewhere else but depending on your connection and the ability of your host to receive these files this operation could actually take some time so and after we've done that let's also tag our work at step 28 like that and push our tags all right so if i say now git tag we should have 26 27 and 28 line up right there so perfect and we should have no status right now awesome as it's tradition after our tagging and committing everything at the end of every chapter we'll talk about what we need to discuss in the chapter that is to come and um i can't believe we're actually getting to this point in this course it is such a huge moment both both for me and i hope it is for you as well because we are actually going to submit our ios application to the app store so without further ado if you want to get some refreshments please do and i'll see you in the next chapter hello and welcome to chapter 47 of the slatter course uh we've been waiting for this moment for a very long time now at least i have so that we have been developing our application using block we've been doing a lot of work with widgets we've prepared splash screens icons etc etc we've even got our hands dirty with figma a task that maybe many of you hadn't done before so what is left now well we're gonna send our application to the ios app store and it gives me really a lot of pressure pleasure to actually announce that that we're gonna do this so what do we need to do in order to be able to interact with the app store and also in order to be able to create your application of course you you're going to need to have a macintosh and that is as i've mentioned an unfortunate fact when you're dealing with ios development but if you don't have a macintosh you can always contact a friend or maybe you use a service on the internet that can for instance take your source code and build your application for you i don't know if those services exist however let's just accept the fact the unfortunate fact that you'll need to have a macintosh in order to build your application and send it to the ios app store so what do we actually need you see when you create your application for um for apple you need to bundle it up inside a file which is pretty much just a zip file but its extension is called ipa and this zip file in essence contains your entire application bundle all the resources and all the signed binaries from your side and then you'll just need to submit it to apple and then this submission is going to go to something called app store connect and um we're going to now talk about app store connect actually and what that is so you see when when you're developing your flutter application for instance and you're talking with firebase then inside of your code you're talking with the firebase sdk but on the backend side of firebase then there's an entire console so there's in the console.firebase google.com i think it's called or if you just google it and say firebase console you'll get to that point and app store connect is the firebase console for ios developers so it is where you basically manage your applications the reviews that are submitted to your applications you can respond to those reviews so it's like the back end um is kind of like a front end for app store's back-end you could say so it's your portal basically to to the app store as a developer and google also has something similar which is the google developer console excuse me so what we need to do now in order to be able to continue we need to actually create our applications on the app store connect so what i'm going to do in here is i'm going to bring up app store connect and i've already logged in with my developer account and let's go in here as you can see these are some of the apps that i'd submitted to apple previously if i can increase the size of this let's see if it works yep all right so what we need to do is in order to be able to submit our application if we haven't done that before for this particular application which we haven't we need to create an application here on app store connect okay so please go to appstoreconnect.apple.com and then you'll be presented with a screen that asks you okay what do you want to do with app store connect and it kind of looks like this my apps app analytics etc etc and this is actually i'm assuming that you have admin access to app store connect because apps are connect like many other frontends it has permission it's like permission based so if you're for instance working with a company and that company has invited you to their own app store connect account and depending on the permissions that they set for you you may or may not have access to either one or all the apps so it is also app-based the permission so like and i can invite you to my app store connect and only give you access for instance to this application and only give you a very limited access or admin access okay so if you don't have access to this app sections because you're invited as um as a user to someone else's app store connect account and they haven't given you the access to access their application so you need to ask them for permission basically to increase the permission level for you so let's go ahead and press this plus button and this is in here we're going to say new app and in here it's going to ask you okay what kind of app is it it's an ios app it's not a mac os like we haven't really worked on a native mac os application although users now with m1 processors on macintosh with macintosh which are arm based they can actually install ios applications as you'll soon see so this application that we're developing flutter we didn't actually create a macintosh target for it but even though it's an ios application you can still install it with test flight or later when it's actually released on the ios app store you can install it with the mac app store on your macintosh so it's absolutely lovely okay so here one you need to do in the name field you need to find a unique name in the entire app store there are millions of applications on the i'm actually making up this statistic i don't know if it's like hundreds of thousands of applications or millions but let's just let's just say millions because easier to say all these applications are in the app store you have to find a unique name for your application and remember you can't use reserved words so if you look in here if i cancel this if you look in here this is not an accepted application name so i just i've prepared this in here just to demonstrate it for you that if you use for instance a name like firebase things like that probably apple is going to reject your application and definitely google is not even going to allow you to go to the google play store with a name with a part of your application name being a reserved word like a product such as firebase so you have to find a unique name that is not reserved so let's just say ios and what should we call this i mean in our application we call it now my notes i'm pretty sure if you say my notes that name is already taken so let's say my awesome notes something like that as you can see it says it is the name that will appear in the app store okay my awesome notes and in here in this box the primary language we're going to choose english and we're going to choose us because we didn't really focus on separating our language like how we actually interact with the user with our strings in the application to make sure that it's like british english or us english so let's just go with the international us english in here and in this box you're going to be asked to actually choose your bundle identifier and app store connect has then after you log in with app store connect it's going to hook into the developer account for this user that you logged in with and it's going to pull all your bundle identifiers into the app store connect so you don't have to type it by hand so let's go find our my notes application as you can see in here it's as epic salty my notes and for you it may be something else okay so i chose that and then sku is a unique id for your app that is not visible on the app store so this is mainly for you sku is kind of like it kind of comes from like um old school when you had a normal physical store and your products had kind of like an identifier so this is an identifier for you it may appear some places like when you're extracting some reports from apple to see okay how many unique users do i have how many unique installs do i have etc so this sku is mainly for you it's an identifier so you could just go with something that makes sense to you and in here i'm just gonna say zero one zero one zero one or this and then one one one one just making things up okay and user access in here you can say you you can limit which user see this app in the app store connect if you select full access all your users will have access to the app so this is like you limiting who can in your app store connect account who can have access to this application and since i don't have any guest users in my private company's account i'm just gonna go with full access but if you're working with like if you're if you're the account owner and then you have some other people invited to app store connect that don't want that shouldn't get access to this account you could just go in here and basically say limit the access to this application to these accounts but i'm just going to go with full access okay i'm going to say create and in here is the place that you may actually get a problem with the name of the application so let's just try it out and see if my awesome notes is some name that somebody else has taken and we'll get to know that soon and from from the looks of it it seems like that my awesome notes was such a lame name that nobody has taken so so that's great for us so um now we've created the application and um that part is basically done so as you can see in here the first thing that you have to enter in this screen let me actually increase the size and let me change the screen layout a little bit here okay so the first thing that we see on the screen here is that uh there's a version information and also there's app previews and screenshots and this is the place that we're gonna upload our screenshots to the app store as you can see at the bottom of the screen it's very important that you take your screenshots first on an iphone 13 pro max because that is the iphone with a six and a half inch display and you may be tempted to just try to take your screenshots on an iphone 13 pro but if you do that then you'll understand after uploading them you'll get an error from app store connect saying that the resolution isn't according to what is expected so what we need to do here is to go to our iphone um simulator so and i have quite a few of them here so this is our iphone 13 pro this is our iphone 8 plus and also we have our iphone 13 pro max so now our responsibility is to actually take the screenshots on this simulator however you'll notice that we have a little problem in here well problem problem but for taking screenshots this is a little bit of a problem in that we have this debug manner here that i am that flutter creates by default so if i zoom in a little bit here you'll see that it's it's just saying debug right here and we need to make sure that we remove that before taking our screenshots so what i'm going to do is i'm going to go back to our source code so let's go in here and you can see at the moment the application's running on iphone 8 plus which is the simulator to the left hand side so in order to remove that debug banner what you'll have to do is to go to your main um dart file as you can see and go to the main function where you've created the material application right after the title or even before you can just say banner which is debug show check mode banner and set that parameter to false and then i'm just going to do a hot reload actually hot restart we have to do so oh i'm not even running it so let's just go flutter select device 8 plus and then i'm going to say run without debugging so you need to ensure that you remove that um debug show checked mode banner and i started not remove it you have to remove the banner by setting this parameter to false and now it's going to basically run the application on iphone 8 plus and it's going to show us the results so this debug banner is going to go away after doing that when we see that it's working on iphone 8 plus for instance then we're going to do the same thing do a flutter select device and run the application on iphone 13 pro max so this process depending on your machine depending on your settings etc it could take a while so i'll just wait here and do this now it's running okay that's eight plus that's great so now that's done now i'm going to close this and stop the debug process and say flutter select device and choose iphone 13 from max and do the same thing run without debugging okay and then again depending on the machine that you're running this command on this process could take anywhere between a few seconds to maybe even a minute or even maybe more so i'm just gonna wait here for this process to go through and um while that is actually happening you'll also need to know that you need to take your screenshots on iphone 13 pro max and iphone 8 plus in order to be able to cover all the required screenshots for app store connect so since we don't need iphone 13 pro i'm just going to minimize it right now into the taskbar and here is iphone 13 pro max so let's go ahead in here and take some screenshots so i'm going to minimize iphone 8 plus as well so we have this in focus so what i'm going to do in here is i'm going to go to this login field and at the moment as you can see i can type in this field because this is a simulator but i don't see the keyboard but in real life when users actually download your application and run it on their iphones they're gonna see a keyboard so it is a lot more realistic if we bring the software keyboard as well on the screen so to do that on your macintosh we'll just have to do command k for keyboard and that will just bring up the keyboard just like this so what i'm going to do since i don't like this carrot that at the moment is blinking right there what i'm going to do is just wait until that carrot appears and just take a screenshot of this iphone 13 pro max simulator and the way to take a screenshot on a macintosh on an iphone simulator is to press command s as in screenshot or save okay so i'm just going to wait for this care to go away and sorry about that i'll just go also here in desktop and remove everything that was created already so here's the simulator and here's the desktop then i'll wait for the care and it went away i took a screenshot so let's go ahead and do the same thing in forgot password screen for instance and i'm just going to wait for care to go away took a screenshot then let's go back to the login screen and then to the register and right here as the care disappears i'm going to take a screenshot as well so this is going to be our third screenshot okay so we have a screenshot of the login screen the register screen and the verify or was it verified i forgot my password sorry okay so now i'm going to log in with a user that already exists in the application so that we can take a screenshot of the main interface of the application as well so i'm going to take a screenshot of this with command s on my macintosh and maybe for the fifth screenshot we're also gonna take one from where you're in the screen and editing your notes with the keyboard up as well okay gonna wait for the chara to go away and i just took a screenshot right there as well so now you should end up with five screenshots for your application so if you have a look at them they should kind of look like this this this this this and ensure that also you don't have that debug manner by removing the debug show check mode banner and after doing that if you're already running a debug session on your simulator for instance you have to do a hot restart remember hot reload is not going to take it's not going to take the code in your main function into effect all right so now we have five screenshots in here so i'm going to go back to app store connect and let's then tap here or click here and view all sizes in media manager okay and let's go to choose file in here and then choose all these screenshots and i'm just gonna say upload all right so now in here you have basically the chance to reorder these screenshots so i think i'm gonna put maybe the login screen first then i'm gonna go to the register and then forgot password and i'm gonna then put the main interface of the application here and then the actual new node screen okay so you can see at the moment when uploading the six and a half inch display screenshots the five and five and eight inch display screen is also using the six and a half inch display screenshots so they're the same screenshots so you don't have to upload them again however then you have this five and a half inch display and which you also have to upload your screenshots for and that is what we need the iphone 8 plus for so we i'm just going to minimize this and then i'm going to bring up iphone 8 plus to the screen and we're going to do the exact same process here so bring up the keyboard as the carrot goes away take a screenshot of login sorry i'm going to go to forgot password screen carrot goes away take a screenshot then i'm going to go to a register screen carrot goes away screenshot and in the login screen i'm going to log in with a user that already exists in the system if i can spell and now it's just beach balling on me so um at oh it's my keyboard by the way i can't see the keyboard so i can see it's been switched to unfortunately swedish so i'm just gonna switch to english here english and it's not helping me really so let's see if it can switch to english please english for some reason it's still showing the swedish stuff in here and i don't really know why so i'm just going to say gmail.com and foo barbados okay he's i mean an iphone simulator is also software so it could be buggy okay so then i'm gonna take let's see what screenshots we've taken so three screenshots so far and let's go to the main ui of the application take another one with command s as i've mentioned before and let's go here as well into oh is this screenshot gonna go away soon hopefully go away please it's not gonna go away please go away okay i think iphone 8 plus is having some problems so what i'm gonna do is i'm just going to close it and then say open simulator and let's go to 8 plus and i can see after i close the 8 plus simulator it actually saved the screenshot so that's great all we have to do is just to go back to our application and right here in the screen as the keyboard is displayed on the screen after the carrot has disappeared i'm going to take a screenshot i'm not sure if i actually did it at the right time without the carrot on the screen so let's have a look please go away okay so this is the screenshot so now we have five screenshots on iphone 8 plus as well so i'm gonna basically delete these screenshots that we took from the iphone 13 pro max right there and let's go to the five and a half inch display section here in app store connect and say choose file and i'm then going to choose all those screenshots that we took from iphone 8 plus and reorder them so let's say log in first then we have register forgot password and then main interface of the application and then new nodes and this is exactly in line with what we've done in here so it's just a good idea usually to make sure that your screenshots are lined up in the same order for different devices okay so now you can see all those three other screens screen types are using the iphone 8 plus i think simulators screenshots so okay yes iphone 8 plus so now we've uploaded those so as you can see more screenshots are already there now so iphone 8 plus is also uploaded and we're done so what we need to do now is to bring up the ipad pro 12 inch simulator as well so i'm going to go here to this simulator and say file open simulator and then say ipad pro as you can see we have to bring ipad pro 12 inch so i'm just gonna click on it like that let's go to um visual studio code and say select device and then i'm gonna choose that ipad pro as it is there and then i'm going to stop the debug process on the iphone 13 pro max and then say run it on the ipad pro and if you're lucky then this process is actually going to go quite fast because the application binary has already been compiled and it should pretty much be the same application running on an ipad pro 12 0.9 inches so again depending on your machine this process could take anywhere between a few seconds to a few minutes even and let's see here so let's go in here and you can see the first section in app store connect for ipad is asking you to upload for ipad pro third gen which doesn't necessarily have to be third gen any ipad pro of 12 and a nine inch display is going to suffice so here's our application it this screen is obviously ginormous so i'm gonna go here bring up the keyboard and take a screenshot and then go to forgot my password take a screenshot then go to back to login and in the register screen take a screenshot all where the carrot has disappeared let's just double check this and i'm going to remove the iphone 8 plus screenshot so now we have three on the ipad pro no carrot no carrot no carrot and let's go now to the login screen and i'm going to log in with an existing user in here okay foo barbat login and now you can see the main interface of the application let's take a screenshot of it and then go to the first note bring the keyboard up like this and without the carrot take a screenshot i actually think i i um captured the carrot unfortunately in this last screenshot and i can see a little bit of glimpse of it there so i'm gonna delete that and i think i did it actually again to take a screenshot basically of the same screen with the carrot so let's see if the ipad's going to help us soon where's the screenshot there i can see the carrot again a little bit so this is a tough one now all right i think i got it this time so let's just wait for the screenshot to appear here okay and there is no carrot so that's great so now we have basically our screenshots for ipad 12 and a nine inch display let's go in here and say choose file and i'm gonna select all the screenshots for that ipad and put them in order so i'm just going to say the login screen first then register then forgot password the main interface of the application and then the note screen okay so as you can see the 11 inch display is using the 12 and a 9 inch display so that's really great however the ipad pro here the second gen to 12.9 inch display um is is i mean these it's not using this 12 and a 9 inch display of this ipad so what could we do here can we go in here and say choose file and upload the same screenshots again and it seems like we can so that's not a problem let's just reuse the same because it's the same screen size so it's a bit strange that i app store connect is not automatically using this 12 inch ipad screenshots for also this 12 and a 9 inch display even though they're the same so i'm going to bring login to the left then i'm going to bring register here for god password like that and then the notes and then the new note so now you can see all your screens are now set all the snap all this screenshots are set for both iphone and ipad so after uploading all our screenshots then we can actually go and set the basic information of our application so so let's go in here inside our app information okay and you can see here there is a note and that is called sorry there's a name inside the app information section then we have the name of our application okay and then the subtitle as you can see it says the subtitle will be reviewed before it's made available on the app store unfortunately it doesn't tell you so much information but every application can have a short subtitle up to 30k up to and including 30 characters so when people search for my awesome notes for instance in app store then they can actually see both the name of the application and a short subtitle so let's say store and store your notes securely with an asterisk at the end okay so that's already set i can see so um and then we could then after making these changes the app store connect expects you to press the save button so that's also good now we've set that so let's go here in this section and go to content rights and then set up content rights information click on it so it says apps that continue or access third-party content must have all the necessary rights to that content or be otherwise permitted to use it under the laws of each app store country or region so we don't have third-party content like we're not actually displaying any videos that's coming from a third party service so here we can just say no it doesn't contain show or access third party content and after pressing the down button we can also press the save button just to ensure that everything is as saved so what we need to do in here also um let's see here a privacy we also have and then we have set age rating across all platforms so let's go ahead and do that and say as you can see here it says select the level of frequency for each content description that best describes your application so we don't have any violence so we say no realistic violence none uh prolonged graphic or sadistic realistic violence i don't even wanna i don't even to say say these things out loud to be honest with you but what you have to do is just to say none to all of these because we don't have any like medical information alcohol related stuff so let's just say none to all of these and uh contests and we don't have that either so let's just say next does your app contain unrestricted web access it doesn't does your app contain instance of gambling no and then we're saying next and you can say our age rate rating result is that people of age four plus can use the application and here make sure that your app is not made for kids because remember applications that are made for kids that have to actually conform to specific standards in order to make sure that eight kids of age four plus are actually safe in the application so um what we could do let's see in here if your app rates 12 plus or lower and you believe it contents may not be suitable for children under 17 you can manually set the age rating to 17 plus so i'm not sure about this to be honest with you but i'm just going to leave it blank at the moment and press the down button okay and then we can press the save button right here so the next thing that we need to talk about now is something called a support url and support url is actually very important and that actually appears i believe in app let's see is it in app information i believe i think it is somewhere around here ratings and reviews app privacy pricing and availability we haven't really come there yet but i believe we have to submit that anyway somewhere and it is here as you can see so support url is actually very very important as you can see marketing url is not optional sorry marketing url is optional support url isn't a support url it's basically a url that needs to be hosted on your website that users of your application if they have any problem with it then they can go to the support url and get some more information about that okay so i have previously created a support url for one of my other applications in my website so let's just say pixel sc and then we're going to say support chords library text okay and as you can see here it's a little text document and says if you have any questions about this app you can drop us a line at support pixel dot so you need to just ensure that you have a support document that you can um place in a website and then you can send your users to that okay so let's now go ahead and create a support document so what i'm going to do in here i'm just going to bring up literally text edit on my macintosh you can bring your um favorite hex editor um um actually my tech favorite text editor is visual studio code but in this case it's just a simple text document so i'm just going to use um normal text edit on macintosh even if you're linux for instance you can just use vim and create or vi you can create a simple document and let's i'm just going to basically copy this and paste it in here and i say contact support and thank you for using my awesome notes because that's the name of our application right it is my awesome notes so i'm going to save this document and i'm just going to say in here let's call it my awesome notes txt and i'm going to save it on desktop save all right did it not save it it is a little bit strange that it didn't save it so let me go back to this text now it saved it yeah it is right here okay so this is a document now text file simple and i'm going to go to my website control panel as you can see here there's a support folder so i'm going to go into the support folder and as you can see i already have four text files in this pixelity se website and i'm just going to hopefully be able to drag a file in there or maybe even upload so i'm going to drag this file boom and i can see it has uploaded now and seems to be it to be honest so let me just go back and see i'm my awesomenotes text file right there and i'm then going to go in here and see it's actually uploaded my awesome notes txt and i can actually see it is uploaded and it's there so if you don't have a website which you should if you're developing applications for ios and android or even if you're developing any applications and putting it out for customers you should have your own website and they're like very cheap ways of grabbing a website with cheap hosting i don't want to go and like sponsor various services and i'm even not even gonna name what i'm using but you can google that or just search online for a cheap hosting and creating a website of your own okay but since this is the outside that's outside the scope of this course i'm not going to talk so much about that okay so now we have this my awesome notes and what we need to do is to go ahead and add this support url so i'm going to copy it here and go to app store connect and in the support url i'm just gonna save it there i'm gonna press the save button okay so that's that and we also need to make sure that we add some other information in here promotional text description and also keywords and etc okay so these things are very important and we need to make sure that we fill these out so um let's see actually here okay so in the promotional text let's just enter in some information here as you can see this commercial text lets you inform your app store visitors of any current app features without requiring an updated submission okay so let's just say use my awesome notes in order to securely store your notes in the cloud all right and description and this app sim this free app allows you to store your notes securely on the cloud and um and that's it i mean they're very similar to each other but that's okay too and for the keywords in here you have to enter i think up to it doesn't really say how many yes 100 characters you have and you have to like comma separate your keywords in here so i'm just going to say and notes and secure wow and make sure you don't have to actually have um let's see boom i don't think you have to have space between them and i'm just going to leave it like a notes secure cloud okay these are my keywords so i'm going to save this and remember we're in here in the ios prepare for submission section so that's also done and our app version is right there copyright we can just say 2022 pixelity uh a b all rights reserved okay these are just big words don't worry about it and um and that is pretty much it so um i don't think we need to do so much more to be honest with you in here and uh we don't even have to have the signing required for now and let's see and also need to go to contact information in here so let's say vandal and my last name and then i'm going to enter some fake phone number right now something like that and here's my support at pixelity and like that no signing required and here where we have the version release as you can see it says this app version can be automatically released right after it has been approved so there you have a few abilities to how you want to actually release your application so after you send your binary to apple you can choose for apple to either automatically release this version to all your users in the app store or you can say manually release this version meaning that after your application has been accepted by apple and approved by apple you can go manually press the release button wherever whenever it suits you best or you can say automatically release this version after app review no earlier now so you can set a date for it but we're gonna say manually release this version okay and after all of this i'm just gonna save this information right there and let's now go to app privacy so this is also very important to remember to do because i don't think um that we have actually yeah i actually believe here now that i can see that i've prepared some information about this in the upcoming chapter so we're going to take care of privacy policy in the next chapter so but know that it exists right there and we have to fix it soon so then what we need to do is to actually make a build for apple because this is like the most important part and and you need to make sure that you followed like the first chapters of this course where i talked about preparing our application for ios there is a chapter in the beginning of this course where we actually talk about creating our certificates and profiles and all of that for for ios distribution so i'm assuming you've already gone through that so we don't have to take care of that now all right so let's go now to our application in xcode let's see if i can bring up xcode it is somewhere around here so there is our application and i'm just going to go into runner and have a look at signing and capabilities and release and i can see that there is absolutely no problem with this production certificate and profile so what we need to do in here to make a release for app store is just to have a look at our runner and here change the target to for instance any ios device and then we go to product and then we say archive so this archiving is then in turn gonna create an ipa file for us and as i mentioned in the beginning of this chapter and this is the ipa file that we're going to submit to apple and xcode is going to help you a lot with that i'm not sure if i'm a fan of that to be honest with you i think xcode hides a lot of details and usually i'm used to like doing things in the command line and doing things simply from visual studio code for instance but it is still a good thing that xcode is going to help you submit your application because in the previous versions of xcode like many many years ago xcode couldn't do this so you had a separate application to actually upload your ipa files to app and that in itself was also quite a i wouldn't say a negative body was something that you have to go through so it is a plus and a minus that xcode is going to take care of all of these in my opinion at least so i'm just going to wait here for xcode to do its work and it is very possible that if this is the first time that you're archiving your application with the certificates that you basically created in the beginning of this course it's very possible that when the time comes for xcode to actually sign your binary and all its other related libraries it's possible that your macintosh is going to ask you for the password to this certificate and actually it's going to ask you for the password to the keychain in which on your computer this certificate is stored so this is usually the login keychain so if i go to keychain access in here you'll see that i have my login keychain and i have certificates in here as you can see distribution so this is the sort that i'm at the moment using for duplication and um after assigning this as you can see it's archiving right hasn't really signed things it's very possible that my macintosh is going to ask me for the password to that keychain so it's very close now to finishing the archiving process so excuse me so let's see basically how it goes after after doing that after actually creating our application ipa file we're going to submit it to apple and that app is going to be displayed then first inside here in the build section of your applications store connect view so let's see if we get this password for signing as i've mentioned here at the bottom of the screen so 4660 or 70 files out of 5039 files to compile and creating our binary so it's very very close let's just see if it can succeed in doing that and i can hear my macintosh um and fans going full speed right now and that's usually something you don't hear on the latest uh max or macbook pros because they're usually so silent like the fan almost never kicks in but this is apparently such a heavy process for this macintosh to perform the faster googling full speed so let's see if it succeeds all right and here is where we're seeing that dialogue that i was talking about as you can see it says code sign wants to sign using your van.hawa nippor in your keychain to allow this enter the login keychains password so it has nothing to do with your certificate it's just actually has everything to do with your certificate but the password itself is the login keychains password so it's usually your computer's password so i'm just going to enter that and then i'm going to say always allow all right so after doing that hopefully xcode is not going to bother me with this password again however i know in some older versions of xcode it doesn't really understand when you say always allow so when it comes to signing your application you may have to enter your password up to like 20 times depending on how many libraries your application depends on so i remember this vividly when i was working at a company and a tester i was telling that tester how to compile an archive an application for ios and we both thought that he's entering his password for his certificate incorrectly so and here now we got module shareplus not found and what could that be because shareplus is basically something that we're using in our application as and it's continuing to archive even though it it says that something's failed so all right so now we got an issue here with pods runner framework and this could seem i mean i'm actually quite glad that we're getting these errors and that could some and be because we haven't done a proper pod install so what i'm gonna do is go to visual studio code here and in the terminal then let me actually change the screen layout a little bit so you see what i'm doing so i'm gonna bring this up so you see better what i'm doing and i'm going to go to the ios folder here okay and then in here you could just say pod d integrate basically pod the integrate it's going to remove all your ios dependencies from your workspace and then you could just say pawn install okay and this is gonna reinstall all your dependencies from scratch so let's see and i can see share plus is actually installed now so it's generating the pods project and great so that seems to be fine so let's go in here and see if we can uh do a clean so i'm gonna go to debug sra product clean build folder and let's see if we can make a fresh build and this could actually take some time because now we've really uh cleaned the build art artifact so it's gonna basically start the archiving process from absolute beginning so i'm just gonna be quiet for a while and let us do its work and let's see if the archiving process succeeds okay so here's the result of actually archiving our application again and we're seeing the exact same problem now after doing a podly integrate and also doing a completely new pod install so we're seeing the exact same problem with share plus say module share plus not found and this could be a problem with how we've done for instance our um pub get and to be honest with you i could cut this out of this whole video but i'm so so glad that we're seeing these problems because archiving an ios application and simply it's not always going to go fine even just doing the same thing for android it's not always going to go fine and if i cut this out of this video you you will be thinking that everything is going fine for me but things are not working for you and then you'll start blaming yourself but i really want to keep these stuff in this course so you see that well a person like me trying to tell you how to do things also needs to understand himself how and why these things are going wrong so in my guess in this case since we've already done a pod install it would be to actually go and clear the build folder for our entire flutter application and also do a flutter pop get from scratch so let's go ahead in our flutter application in here and at the bottom i'm just going to say fluffer clean and that's going to clean the artifacts for ios and android okay and then you're going to get a lot of errors in your application because then it doesn't understand anything so we then say flutter pop get all right so that's gonna do its work and get all your dependencies from scratch basically and install them in your application all right then what i'm gonna do in here is to yeah we could just leave it like that now and go back to our xcode and then try to archive the application from scratch let's see let's see if this time it goes a little bit better and hopefully it shouldn't take so much time this time but you never know with xcode and with ios development it has its own antiques so let's just wait and see after doing a pop get if this process is going to go through or not so after xcode has compiled the application again i could see the same problems as as we had before so meaning that our pod the integrate and flutter clean really didn't have so much effect on the application itself now since i've been doing ios development for a very long time i still have some tools in my in my belt that i can drag out and use and one of the first things i would use as a software engineer and an ios developer is just to first have a look at our deployment ios version and here we're supporting ios 9 and it's very well possible that this sharing capability that is built into the plugin that we're dragging into our application isn't compatible with this ios version so first i'm going to bump this to ios 13 at the moment at the their ios 13 14 and 50 are very popular so there are the latest versions of ios at the time of recording this um course so first i'm going to do that the next thing that i'm going to do is to from our project in here so i'm having a look here as you can see i'm in the ios folder of this notes project so let's go in there then the first thing i'm going to do is to perhaps remove the um i wonder if i should actually remove the pod file as well maybe let's just remove the podfile.lock and remove also all the pots from the project okay so then i'm gonna do fluster clean in here that removed really all the pots from the project and then after undoing that i'm going to have actually a look at our pot file to have a look at all our ios dependencies and see how they look like so i'm going to stop the execution of the program and then i'm going to open a file called pod file and this is where all your ios dependencies basically are stored as you can see the platform is ios 13. so it was strange that our deployment target was ios 9 so this could be a potential source of problem and after doing that then we have our pod file and yeah this this looks fine as it is so um let's then go after into the terminal and after flats are clean let's just say flop flutter pop get which is going to redrag our dependencies into our flutter project and ios project for instance then and we can then go back i'm actually going to kill xcode and open the ios folder and open the project workspace again and i can see here at the moment the pods aren't really installed so let's go and do the installation of pods ourselves so i'm going to say pod install this is going to install all the dependencies and let's have a look in here and say what it is talking about cloud fire support as far as store using firebase is defining okay those all look fine here says coco pods didn't see the base configuration of your project because your project already has a custom config set in order for cocoapods integration to work at all please either set the base configuration of the target runner to target support files blah blah blah or include the target support files in your build configuration so this could actually be very important as we can see in here so maybe there was a problem in setting up our project with flutter create when we said we created our application to begin with but let's just keep this in mind and try to go in here and open our workspace one more time and now i can see all the pods are in here development pods okay share plus is right there pod okay and the pod spec what is the pod spec says it actually says the platform should be ios 8 so it supports ios 8 so that's not a problem so what i'm going to do now is after doing all these things i'm going to basically try to build this project again so i'm going to do a clean here clean build folder with command shift k so blink basically clean your build folder and all while all of this is going on editor functionality that's that's fine so i'm going to basically start doing a um product and archive again and then i'll see you on the other side either this succeeds or fails and if it fails we're gonna fix it so let's have a look okay now i can see after doing all the gymnastics that i just had to do then our application has finally compiled without a problem and to be honest with you this is one of the things that i believe many courses are missing in that when you go through distributing your application you actually go through a lot it's not just that you press a button and submit your application and you're done well usually if everything is set up correctly then that is the case however you have to set up everything correctly so what happened in here is that we have to issue a few things what i did just to name them step by step is that i first bumped the deployment target of our application from 9 to 13. so you can find that by clicking on your workspace in xcode then clicking on your runner target general tab in here and then the deployment information i bumped it to ios 13 so that's the first thing that i that i did however i don't think that that necessarily had anything to do with fixing this problem the other thing that we did from terminal was to clean all our pots and i did that by saying rmrf pods now we issued that command from the ios folder if i open this ios folder you'll see that there is a folder in here called pods what are pods pods are basically your applications dependencies for ios that's how flutter manages your ios application dependencies so all these libraries for instance like firebase and this sharing library that we just dragged in they're using basically they are dependencies that flutter manages using cocoapods which is a third-party software and you have to have cocoapods installed on your computer in order to even be able to interact with pods so there's lots of information on the internet on how to install cocoapods but it's usually pseudo jam install cocoapods and i think maybe you can even use homebrew to install cocoapods but i usually use sudo jam or jam in this case but you need sudo usually to install cocoapods so so what we did we removed the pots folder we removed the podfile lock which for you who are like comfortable with backing the web development with npm this is this is like your package lock file and if you're not comfortable with back-end development basically a pod file lock is a file that stores information about all your dependencies which are currently installed whereas the pod file stores information about which dependencies you need and pod file log stores information about the ones that are integrated right now into your application so we remove that just to ensure that on the next pod install all our dependencies will be freshly installed and regardless of what is inside the pod file lock so there were a few steps that we had to take but finally we manage oh also we don't forget flutter clean we also issued flutter clean so after all these steps we finally managed to build our application and as you saw in this screen we came to this archive section so i want to have a look a little bit here at my notes to see um so yeah we've done the password signing etc etc and now we basically um basically created this ipa file in here so one you need to do in here then you press the distribute app button and say app store connect and say send send and this is going to do some analysis on that binary for you and it's this is going to connect to app store connect and some of you in here may immediately get an error saying that well i don't know how to connect and that's because you haven't entered your um profile information in xcode if you go to xcode preferences there is a section called accounts and you need to ensure that you basically add your app apple id with your account in xcode for any of that for the distribution to actually work at all so i'm going to say app store connect here and next upload to app store connect next so let's go in there okay and it says okay upload your app symbols manage version and build number i don't really like that so we're gonna take that off so we're not gonna use that okay and let me just make the screen a little bit bigger and press next in here and here you have to select your uh profile and seems fine press the next button in there and this is going to contact app store connect and depending on your application size this could actually take quite a long time for some of the applications that i'm working on not personally but for various companies even with my thousand thousand download upload um [Music] internet connection this process could take a long time so let's see how long it takes because you see during the upload process it's not just uploading your binary it's actually contacting apple and even validating a lot of your assets like your images it's valuing your icons it's valid validating even if you have other resources in your application and i believe it even checks like if you're making any api calls which you shouldn't be making and i'm not talking about network api calls but i'm actually talking about ios sdk api calls for instance if you've hidden some work in your application which is making uh calls to some um private apis at the ios sdk level so now we're just gonna let it do its thing and upload and um we'll just wait until it's done okay well the upload process seems to have gone actually a lot better this time and um and i actually have to really confess to something in here in that the upload process for me took a very very very long time i'm talking about upwards of 30 minutes even though i'm on a thousand thousand um fiber optic download the upload speed um for my internet connection this still took a long time and this could either be a temporary bug a glitch on apple on apple's app store connect website or it could just be something that well from now on things are gonna take a long time you never know what apple so that's unfortunate but at the moment it's gone through and i can see that um you will get this message telling you that your app was uploaded successfully okay now let's talk about a um a push notification email that you'll receive from apple that will look like this after submitting your application you will probably receive an email from apple that looks kind of like this and in here as you'll see it says we i i want more issues with recent delivery of your application my awesome notes your delivery was successful but you mentioned you may wish to correct the following issues in your next lorry missing push notification entitlements and this may be a bit troubling for some developers but this is simply because we're at the moment using firebase in our application on firebase is able to handle push notifications so that you can send a push notification from firebase console to your users however our application isn't taking advantage of push notifications at the moment so you can just disregard this email and just don't try to even fix anything because all this email is saying is that we've analyzed your binary it looks like you are accessing some push notification apis however you forgot to enable push notifications for applications so and this is simply because when you bundle your application and send it to apple as an ipa which is something you probably didn't actually look at but if you go to visual studio code sorry if you go to xcode in this archive browser right click on your runner and here and say show in finder you'll see this xcode archive file and say show package contents and in here you'll probably see some products and applications run our app so this whole thing is like your ipa file that apple has received now in this runner application there is information about what kind of like libraries it has included in itself and you can actually right click on run or app and say show package contents and in here you'll see all the frameworks that your application ships with and you can see firebase etc etc so one of these frameworks most probably one of the firebase frameworks is internally using it has it is using some apis related to push notifications but that doesn't necessarily mean that it is active and it's actively being used so that's just an email that apple tells you that hey you may have forgotten to do something but you can just disregard from this email and say no i didn't forget anything because we don't have push notifications in our application okay so that's that email and um so that seems to be fine and after that email you'll probably also receive an email that looks like this telling you that hey your application with this sku has now been submitted and has completed processing and this this email literally means that after this application's finished processing you're able to install it on your ios or mac device and you can test it as you'll see in the next chapter but as we usually do in every chapter at the end of every chapter we commit to what we've done and we make sure that we commit and tag those changes so let me do some reshuffling on the screen here and let's go to and i'm going to close xcode here like that go to our application my notes to terminal and let's just see git status a few things change so i'm going to go cd get status in the main folder of our application my notes because i was in the ios folder so i just did cd dot dot like this so now i'm in the main folder grid status shows this and i'm just going to say git add all right and let's just have a look at our logs the last commit was step 28 so let's just think it's commit step 29 as a caption at the bottom screen indicates and we just push our changes after that is now let's just tag our changes as well and say step 29 and hit push tags just like that all right so that is now working as expected so what uh we usually at the end of it at the end of every chapter is that we talk about what we when we are going to discuss in the following chapter and what we need to do in the next chapter is actually release our ios application we've sent it now to apple and apple has finally finished processing that and build meaning that it's ready now to be actually submitted to apple and that's what we're going to do in the next chapter to submit the app for release to the app store so i'll see you there hello everyone and welcome to chapter 48 of this flutter course in previous chapters we've been working with creating an ipa file and sending it to apple and in this chapter we're going to make sure that we're releasing that ipa file meaning that we're going to tell apple that hey we're ready with this ipa file and we want you to um review this file for us and the review process for apple and and google are a little bit different in that for instance with apple sometimes uh there's an actual user looking at your application and sometimes if you for instance request a um a fast review from apple they may not even look at it and they may just say okay it just works it's it doesn't crash and then they it just goes through um and for google it could also be a completely different process but we're right now in this chapter we're going to focus on how ios app app submission basically works okay so when you send an ipa file like we've done to apple it will be available in a place called test flight so let me bring our web browser to the screen and let's go and see if we can if you can actually bring the views as we had before so let's see app store connect and i've restarted my computer since last time so i may have to basically log in again and thank god i didn't actually have to restart the whole process and actually grab my security key in here so it just allowed me to log in so let's go to my awesome apps in app store connect and then you'll see a tab up here called test flight and test flight as you'll see now our build then is available in here and it's ready to be tested basically so what we need to also do is to go in here in the missing compliance and then tap on this manage and it says does your app use encryption select yes and and it says export logs require that products containing encryption must be uh properly authorized so in here we could just say yes and it says export compliance does your app qualify for any of the exams provided in the category make sure that your app meets the criteria actually we could go previous and just say no in here because we're not directly using um if you it is your responsibility to comply with export regulation and you should revisit this question if your encryption exists i'll just say blah blah blah okay now okay and then we say start internal testing okay so now that compliance error is going to go away so now that we've done that you'll see that here in app store connect there is a section called test flight and in here you have the ability to for instance invite third-party testers to your um to test your application and you are also allowed to give access to your application to users who you've invited to app store connect so it is very very important to understand the difference one is internal testing and the other one is like if you want to submit your application to be tested by third parties like someone who doesn't work for your company for instance so in this case we're just going to use internal testing in this chapter but just know that test flight is on ios and mac os an application that you can actually download on those operating systems and you can use test flight in order to test your own ios applications or mac applications before you submit them to app store okay so that's where test flight now that we're talking all about all these let's just also make sure that we know we have a little bit of a security problem um we haven't really talked about it so much yet but i i built this um with uh uh in swedish you say midfield and that is like intentionally intentionally i built this into this course so you'll see how the resubmission process also works so if if we bring our code let's let's bring our mynotes code in here and have a look at our um i believe was one of our services notes service oops no service is completely oh because that was the crowd service so let's have a look at the service and cloud note and we have crowd cloud storage cloud firebase cloud storage it's called okay i'd forgotten the name and we had this little all field in here you see so what this all field at the moment is doing is saying that go get all the notes in all the notes in the notes collection so that's doing that and then from all the notes remember all the notes not only your notes it's taking and creating a cloud note and then it's filtering them out by who you are that is a huge security problem because by doing this subscription and getting this stream you're pretty much reading everyone else's notes as well what we want soon we're gonna fix that don't worry about it what we want is to not even allow any user to read someone else's notes okay and then we're going to change this implementation of all notes and resubmit our application to apple so i didn't want us to submit an app to apple and then to google and then have to resubmit it in both platforms because as i said planned this so i just wanted us to submit something only to one platform and then draw it back and then send it again but don't worry about this yet i'm just giving you some preparation of what's to come so what we need to do now first is to as the caption at the bottom of the screen in the case we need to install test flight for both ios and you also have to install it for um your mac on on the mac you can just go to app store on your macintosh so app store app and then search for test flight okay after search for test flight you can install it with this install button i have it installed already on my computer so i don't see a install button in here i can just open it and after you've done that um for your macintosh you'll also need to install it for your um ios device and here i actually have my iphone my little iphone 13 pro max here and i have i'm mirroring that iphone here on the screen as you can see so what you can see on the screen is actually my iphone right here okay and test flight is an application which is available right here so this is the test flight application on ios so at the moment you can see that i don't have access to my nodes application but we're going to fix that soon or my awesome notes as we call it okay so let's go ahead in here and have a look at the next thing we need to talk about and that's adding a user to to test light so how do i get access to um to this build that we've submitted so that i can test it with test flight well the user that i've used for testing in here and i know that user it's pixelity.sweden gmail.com so what i'm going to do now is to invite that user to test this build so let's go to internal testing and press the plus button and in here i'm just going to say my users okay and then press the create button and in here you'll see a plus button tester 0 and i'm just going to say plus and in here i'm just going to use a pixel to switch so i'm just going to say add in here okay and it says one tester has been added to this group and that's pretty much it so i don't have to do anything extra there so what i'm gonna do then is going to wait for um an email to be sent by app store connect to my user and it's just been sent i'm gonna open it so you can also see it how it looks like here's the email that i just received so app store connect is telling me that hey you've now been invited to and test this application and you can just go ahead and do it so i'm just gonna tap on view in test flight and this is just gonna work because i already have um basically a test light installed on my macintosh so let me just tap on that and i can see test flight open on a separate screen i'll bring it to the screen here and i can accept in basically installing this application so as the bottom as the bottom captioning indicates we've already looked at the email it looked like this and now we're going to install this application which is a flutter application but we're installing it on a macintosh and that's just great so let's just accept this and you can see now i can either say install or done so i'm just gonna say done so you see it so this is our application here and i'm just gonna press the install button and this is just gonna go to app store connect and grab that binary and bring it down so and i can just press the open button and if everything goes well this is our flutter application running on this macintosh but it is an ios app we didn't actually compile this to be running on a macintosh so everything is just working as it should i can even log in here right like that and then in here it's a foo bar bass log in and i can see my note so it's working as expected so i'm just going to close the app now all right so what we need to do now is to submit this build we've looked at it it seems to be working fine so i'm just going to close test flight here and close this email let's then go to app store connect and let's go to this app store section in here and in this ios app section here 1.0 prepare for submission let's scroll down to the place that says build and we need to then say select a build before you submit your app okay now remember uh if you don't see this blue button in here that's because you've probably just submitted your bill to apple apple usually takes up to 30 minutes or sometimes even more to validate your build so they may not have even appeared in here especially if it's the first build that you're sending to apple it may take a while for them to process it so you may not see this button simply because there is no valid build yet but you can test you can check the status of your builds by just going to this test flight section and just having a look at the version that you've submitted and if there is if that build is still processing it will just say uh paranthesis processing and the icon will just be a little bit grayed out okay so don't worry it's not there's nothing wrong you just have to wait a little bit so in here i'm just going to say select a bill before you submit your app and then say one that build that i'd submitted all right so and then i'm just gonna press the save button so that's for the build so age rating in app store connect go to app information and fill in age rating and i believe we've already done this so if if you've not done that before please go ahead and take care of that but i explained this in one of the previous chapters so you may have to go and edit your age rating if you want to but if you have followed the chapters chronologically you should have done this by this point okay we also need to take care of our app privacy so we need to go to app privacy as the caption at the bottom of the screen indicates and here we have to get started by filling out our app privacy and as you can see in here if you have an application that collects a lot of data you i don't want to scare you but you may kind of be in trouble because you will have to inform apple about all those things what you're collecting from the user okay so let's let's in here let's say do you or third party partners collect data from this app then we should say yes in here right because we are collecting data and that is the user's for instance email address password and notes so let's just say yes in here's a data types that meet all of the following criteria are optional to disclosure the data is not used for tracking we're not using it for tracking the data is not used for third party we're not doing that collection of data occurs only in infrequent cases okay so we pretty much are not doing any of those tracking stuff that they're saying here so let's go in here and say data collection yeah we're collecting your email address and that's it we're not collecting any financial information location contacts user content photos audio gameplay none of that any other user generated contents yes browsing history no search history no user ids screen name handle account id yes we are device id we're not um diagnosis crash data we're not doing that at the moment and other data so yeah this seems fine so for now we can just say identifier to user id we also said other user content because we're collecting the users generated notes and we're also collecting their email address so let's just say saving here okay and it says additional setup required so let's go ahead and fix those now in email address let's go set up email address so i'm going to click there and are we using it for third party no developer advertising no analytics no product personalization customizing what the user sees such as a list of recommended products for no app functionality yes that's what we're doing so press next and are the email addresses collected from this app linked to the user's identity link to the yes email address collector link to the user's identity are there i mean this is this is a little bit of a legal question so i'm not best um placed here to answer this but i mean an email isn't necessarily connected to someone's identity as a person because i can just go create like a private email and no one knows about so i'm just gonna answer no tracking email address okay next um okay doesn't seem like okay do you or third-party partners use email addresses for tracking purposes nope okay and saved okay so the email address stuff is saved now let's go to other user content which is the user generated notes okay so indicate how other user content collected from this app is being used um advertising no analytics no customization no and app functionality of course so let's then go and say is user content collected from the sub link to the user's identity they're used they're linked to the user's email and since we said email is not linked to the user's identity i'm just gonna reason to say no in here do you or third-party partners use other user content for tracking purposes nope okay so that part is done as well then let's go to identifiers for user id so i'm just going to click there and remember user id in here is that uid that firebase creates okay remember that so we're using that for app functionality okay are the user ids collected from this app linked to the user's identity user id user identity i would say yes it is quite obvious so let's just say yes do you or third party partners use user ids for tracking purposes nope nope all right so saved and that's that now you've gone through the privacy policy and this is like that basically what happens is apple will display this to users when they try to download your application this is very important that you fill in to the best of your knowledge and ability this is not the place that you go and fake anything and say try to hide the information that you're collecting from the users it is in the in your best interest in your product's best interest and in your company's best interest to make sure that you fill these in as best as you can okay usually in bigger companies you'd want to probably um consult with a lawyer or somebody who's um good at making sure you're not missing anything so in a big company you usually don't do this on your own but since we're now assuming that you're a simple like a single entity even if you're behind an organization like me but you're a single entity and trying to do this to the best of your ability okay so now what we need to do is also fill in this um let's see here privacy policy so what this is as you can see in here a url that links to the privacy policy privacy policy is required for all apps and as you can see at the bottom of the screen i've actually included a little privacy policy for my own website and i've included that let's see if i can log in in here let's see if i can do it on a separate window so you don't have to be bothered by that because i've actually included that um you know what i will actually do it on a separate screen so you don't have to be bothered by that and um so i will go to i'll go to my hosting website and i'll take care of that and then i'll bring it to the screen so you can actually see it so let's see if i can go to my hosting in here and then go to my hosting basically well all my file files are residing excuse me and i'll bring it in here so let's have a look at this url that i provided at the bottom of the screen you can see pixel dsc privacy policy so i'm going to go to dub dub up there and i have a look at this text file which is right there privacy policy so if i type pixelity excuse me privacy policy you see that there is a generic privacy policy that i've placed in my website and you will need to do the same thing so you'll need to basically grab a privacy policy from somewhere and look at that privacy policy and make sure that it works for you so what i did is i found a website and i'm not just going to go advertising here but you can find free privacy policy written by a very good and smart people and you can have a look at those adjust them to make sure that they make sense for you and your company and for instance in here i've just taken a generic privacy policy let's see if i can find it here so i put my company name in there and i just ensure that it makes sense for my company and i've just basically put it inside that url that you can see at the bottom of the screen so i'm going to go in here at privacy and app store connect and say privacy policy edit and in the privacy policy url i'm just going to say https pixelity dot se and then i'm just going to say privacy policy.txt but for you this should be something else okay and i'm just going to copy that open it and make sure that it exists and then i'm going to press the save button okay so after we've done that we also need to make sure that we've taken care of our categories the categories to which our application belongs so let's go to app information at the bottom of the screen indicates i'm going here in the category and the primary category we're going to say our app belongs to productivity and then it belongs to utilities okay here utilities all right then i'm gonna save this information okay then what we need to also do before we submit our app for review is that just remember this application is going to be reviewed by an actual human so this person is literally going to get this information in the queue of their work they're going to say oh an application called my awesome notes needs to be reviewed and then they're going to say okay they're going to have some control panel on their screen i don't know really how it's formed on apple's site but they're going to then download this application on various devices automatically perhaps and then they're gonna open the app and then like how am i supposed to use this app so it is in your best interest to ensure that you provide all information possible to that person so that they can review your application so what you need to do then is to go inside app here prepare for submission in here app review information and then under notes just tell that person what your how your application works and how they need to register so in here what we're going to say is um you you will need a valid email address in order to register please follow these steps to register now i'm gonna say um open the register view and register with the email and password of your choosing you're choosing wait for a confirmation email wait for a confirmation email from to be to be sent to your email address and in the confirmation click on the link to confirm your email address okay and then step three is go back to the app and in the login screen log in with your email and password and that's it so we've done that now so i'm gonna actually then provide a valid phone number in here and since i don't want to really share my like phone number everywhere on the internet i'm just going to go on to a separate screen here and write my valid phone number in here um but that's my phone number great and let's then go here and then i'm going to press save button as well and then bring the screen here perfect so now i've saved that information including my phone number and everything should be ready at this point so what you need to do then is to go and grab some popcorn while you're doing this hopefully and then you'll just need to say submit for review and it says the items below need to be okay we haven't really done the price pricing and then it saw it says an admin must provide information about the app's privacy practices in app privacy section it seems like we missed some stuff so let's go to pricing and availability and fix that this application is going to be free so i'm just going to say it doesn't cost anything and save that so that's for pricing and let's go to app privacy and see if we've actually missed anything doesn't seem like it but what we've forgotten is to actually press the publish button so let's just publish that okay then we go back in here and then we say submit that's great so now your application is submitted to app store and a reviewer from the app store connecting is going to have a look at your application so that they can confirm that it works according to the information that you've provided and i can see that i actually got an email from apple that looks like this and it says the status of your application has changed to waiting for review so it's not a waiting game so um but before before we actually do all of this we whether apple has had the time to review our application and accept it or they found some bugs in it and rejected our application whichever case we need to draw back this build and i will show you how in the upcoming chapters because we have the security bug that i told you about so for now we can just be happy that we've gone through this chapter we've done quite a lot of work and um pat yourself on the back just great job and grab some uh maybe a tea or coffee and we can get start to actually get ready for the next chapter and i'll tell you actually what we need to talk about in the next chapter and that is this little um problem that we had in the all notes and we need to fix this before we can go live with android as well so now you know what's coming in the upcoming chapters and um i'll see you there hello everyone and welcome to chapter 49 of this flutter course in previous chapters we've submitted our application to um app store connect and we also briefly talked about the fact that we have a little bit of a security problem in our firebase firestore database so let's have a look at what the actual problem is so i explained this briefly in the previous chapters but i'll do it again in here so let's have a look um so if this is our code i'm going to increase the size so we'll see it better and you'll see that when we are working with displaying all the notes on the screen for a user so for instance user a has signed into the application and inside our notes view if you go there we'll see that we're subscribing to all nodes in here in our stream builder so we're saying we're basically building our entire list view which is here now it's list view and we're building it on top of the data that comes from this all nodes function which is at the moment inside our firebase cloud storage okay however if you look at this code you'll see that what it is doing is referring to this node's private um or this node's local variable and which is right here and this notes at the moment is pointing to the notes collection and what it does it literally takes all the notes from the notes collection so this look this essentially means any user logged into our application is truly retrieving all the nodes in the entire database although at the end of that code what we're doing is saying we're okay after we retrieve all the nodes from the database then we're mapping them here to cloud nodes so we can consume them locally and right at the end we're saying hey but we're only interested in notes that are for discard user but even though the current login user is not going to see all the notes in the database but the current user is reading all the notes in the database and if you perform a man in the middle attack for instance if you're using charles proxy on a computer and then you're using your phone and you're using for instance let's say you have charles proxy on your computer and then you're sharing your wi-fi connection from an ethernet connection through wi-fi with an iphone that is running your application if i don't sit in the middle with charles proxy and look at all the traffic that's going from your flutter application to firebase then i can actually see you requesting information about all those notes and then those notes coming back to the application so a man in the middle attack could potentially then expose all data in our database or in the notes collection at least so we need to we need to fix this so what we're going to do is by is to start by removing our application from app store connect if you remember in the previous chapters we sent our application to apple for review and what i've done in here i've developer rejected this application essentially so let me have a look and see if i can increase the size of the screen so we submitted our application to app store connect for review from the apple um team review team but right before it actually went to review i refreshed the screen in here and you didn't see this but i said remove this application from review if you remove your own application from review basically it will become this it will go to the state developer rejected so this is basically informing you that hey it's not apple basically rejecting your application it is you yourself who's done this so so i can show you an example how that confirmation email from apple will look like so i'll open it in a separate screen and it kind of looks like this i'll bring it to this main screen so you see it as well okay all right so there we go so then i received an email from apple that said that status of your app has changed to developer rejected app name blah blah okay so this is the email that you'll receive so i need you to basically reject your application the version one zero that you sent to apple because we have security problems with that application okay and again i've mentioned this in the previous chapters i did this in on purpose so that we can understand like someone because this is the kind of stuff that you're going to go through as a software developer sometimes you're going to submit something to apple or google and then you understand you made a mistake so how do you how do you fix that and i really wanted this to be a part of this um course so you understand how you reject your application how you fix the problem and how you resubmit the application okay but i didn't want to do it for both ios and android because it just gets boring if you have to submit first go through the entire submission from two platforms and then to submit again so that's why we first submitted for ios and then we're gonna fix it and then once that's fixed we're also gonna submit for android okay so after rejecting your application you also need to basically remove your build from this at 1.0 so i i believe i've already done that oh no i haven't so it's actually good i haven't done that so let's go ahead and here in 1.0 and just remove this build okay so we say we don't want to submit anything and then press save okay all right um and also as you can see at the bottom of the screen we're going to update this 1.0 version now to 1.1 so let's go and see if he can find that information so right now i also saw that i got an email from apple and here says okay now it's prepared for submission meaning that it's not developed or rejected anymore and let's just bump this version in here to 1.1 0.0 okay and then i'm going to save it well and here i mean this is kind of like a it depends on your taste if you want to resubmit 1.0 you're more than welcome to do that but it's usually if you change something in your code then it is usual for you to go and update this um minor version and it's called so because this first version is the major version so if there's a huge future in the application and this is the minor version and here is a patch i mean you could argue that we could i essentially maybe change our application version to one zero one because this is a patch but i just choose to do one one zero okay so let's go ahead and i'm assuming that you're doing the same thing because there's some information i'm gonna provide to you a little bit later in this chapter that relies on you having actually changed your app version to one one zero okay so that's that part is done what we need to do now is to go as a caption in case we're gonna go clean all the notes and users in our firestore database so let's go ahead and see if we can get that to work so my notes flutter project so that's in your firebase console and i'm going to go first to authentication to users there's just one user in here i'm just going to delete that account okay then i'm going to go to firestore database and there's probably two notes in the notes collection and i'm going to delete them as well so delete documents there and then delete this document as well okay so we have a clean slate no users and no notes in the database so you may be wondering well if we have security problems with our database shouldn't firebase be intelligent enough to know that and firebase is actually intelligent enough to know that and sometimes you will receive emails from i mean depending on the security holes in your database you will receive emails from at firebase telling you that hey there is something wrong with your security rules and i've prepared some email that that kind of indicates that i just wanted to show you how that kind of email looks like so you can see if you have security issues with your fire firebase and firestore database you may receive something like this you see it says we've detected the following issues with your security rules any user can read your entire database so it kind of looks like this okay so just know that if you receive an email like that then you know at least the reason for it okay and if you're wondering more about like security rules and how you have to configure them although i'm going to tell you how we're going to configure our security rules in this chapter but if you're wondering how to do that on your own and you're curious about reading more about it i've prepared a little link here so let me see if i can actually bring it to the screen by opening a link and it kind of looks like this so you see firebase google.com docs first our security rules and conditions so and so you can read about this and i did that and i got a lot of inspiration from how to fix our security uh problem in our firestore database so i strongly suggest that you actually read this documentation you don't have to do it right now but please just at least um bookmark this page so you can come back to it later okay so now to the point let's go and fix our security issue in our firestore database okay so i've also prepared here how we have to actually do it and you can see the let me actually bring up our security rules so go to firestore database tab in your firebase console and then go to rules okay let's have a look at all roles at the moment and how they're set up so the way it's set up at the moment you can see it says match any database and any documents okay and that's what we're doing here as well and it says match any document in there so at the moment we're allowing read and write access only if you're authenticated so okay so let's just for now say we are allowing create if you're authenticated so we say you should be able to create a node as long as you're authenticated so let's say create and you can see we get some help from firebase as well in here okay so that's that so creation and then we say allow read write and update okay and this is the rules that we're going to write in here you can see read update actually read update and delete so so read updates and delete and the way we have to set it up is of course as you can see in here what i preferred is we first need to make sure anyone tries to read from our database or update the database or delete the document should be authenticated so let's go in here and say okay if authenticated we'll bring that code up here okay but we're also going to add some more information to it and the information should like look like this you can see in this document in here you may be like okay but how do i know because okay before i actually say that what we want is for the currently authenticated user id to only be able to access his or her documents that have the same user id remember in our code we have this user id field let me bring it up here so if you go to our storage here we have these constants and we have this user id field so every node that we store in our firestore database has a user id field so what we want in here is to basically grab the user id from the request so if you say in here request you'll see we have off path resource so let's go off and then you'll see there's something called a uid and that is the user id okay so if we have a look how we have to actually do that so we're saying user request rtu id should be equal to resource data user id and this resource is the current resource that the user is trying to access okay and if you read the documentation that i provided to you earlier you'll you would know this so let's go in here and say okay the request auth uid should be equal to resource beta dot user id because that's the field that we provided um as you saw in the code here so let's then um yeah i think this is good to go so we could then publish these changes and it says publish changes can take up to a minute to propagate and that's completely fine because we're actually going to take some time in order to update our code as well okay so that's our security rule so let's just make sure that they look like this and i'm gonna actually bring it to two lines so you can see it in its entirety um if you need to get some um inspiration from this you can also build on top of this tomorrow so you can add more security to this so you're more welcome to um then what we need to do is start cleaning up our code on the dart site so on the dart side so let's have a look at this code that we've written in here i'm going to change the screen layout a little bit so you see it better so let's go to this function gets notes and you may have noticed it but gets notes at the moment we're not using this function at the moment so we're only using all nodes so let's go ahead and just remove this gets notes from firebase cloud storage okay just like that i'm running the application at the moment so let's just command s and i can see there's no problems because no one is actually using get notes and there's no errors in our code you can see there's no files or folders that are marked as red so um so that's that one that was one of the things that we have to do just to remove the get nodes and then what we need to do in here is to ensure that our when we're actually saying all notes that we are filtering the snapshots before we actually read them so let's just go in here and say notes and before snapshots f like this i'm gonna say where and you can see it says okay which field are you looking for then we say owner user id field name and that should actually be is equal to and we have the owner it's ready right so that's that one and then after that we say snapshot and snapshots map and that's also fine actually so in to be honest with you we could clean this code up as well so let's just say in here and we take this and we say this is our notes excuse me the final notes is equal to that for all notes and we could just return it all right so now we have this and you could basically argue saying that okay we have a where clause in here so we don't have to have this word clause in here and i would actually say yeah that does make sense because yeah why would we have two word clauses so let's just remove that word clause and put the semicolon in here okay so we filter before we read all the snapshots all right we're getting an error in here let me see what the problem could be because there's a map all right so your code basically should look like this right now and what we can do now is to actually put this to test to make sure everything's working as expected so i'm gonna bring our ios simulator in here which the application is running on already gonna do a hot restart and let's just register a user so i'm just gonna say van.np gmail.com foo barbeaus and please don't use this uh password say register and then it says verify email okay and let me go ahead and bring up my mails and have a look at my email and see if a verification email has been sent to me and we've sent an email verification please open it to verify your account and i hope i actually entered my email correctly because i haven't yet received a verification email so perhaps i could open up gmail in a separate tab because i'm using gmail at the moment for that particular user and see if that email has appeared in my gmail inbox okay i'm gonna switch users all right let's see and this is i'm doing this on a separate screen so that's why you're not seeing any of this happening um i can't see really any email at the moment so um let me go ahead in our firebase console in here so um let's go here and let's go then to authentication and i can see that there is a user here and that is actually correct but i don't see any verification email being sent to me so let's go ahead and have a look at our register view and let's have a look at the button implementation if we actually forgot to do something so when we pass this register event you can see auth event register then we have to go to our off block and have a look at how we've implemented implemented that i can see that we say create user and then we're awaiting on the provider send email verification so it seems to be working fine however i still haven't received any verification email and that's why i'm just going to say send email verification here on this screen and by pressing that i'm just going to refresh my emails and now i can see i received a verification email i'm going to bring it here tap on the link and i can see that i saw this um i can see that your email has been verified was displayed to me so that's great let's go ahead now and um go to the application and i'm going to restart here go to the login page and i'm going to log in with that user fu barbaz log in with the user and no problems i can log into the application press the plus button and i'm going to say my first note okay that's saved and then i'm going to save my second note all right and that is also saved then i'm going to log out and try to log back in with another user so let's register a new user because remember we deleted all our users from firestore database so who are about again please don't use this password and i'm going to have a look at my emails then and i can actually see a new verification email was sent to me so that's perfect i'm going to bring it here if i can open that email it looks like this i'm going to verify my user great then i'm going to restart the process and try to log in with that user okay through barbaz log in with the user and i can't see van dot's notes so i'm going to say another first note another first note and create a new note say another second note all right so after these two users have created their own two individual notes let's go ahead in our database refresh the users we can see there are two users in here one starting with pg which is this pixelity and then there's a 9v which is the other user okay let's go to our database and see how many nodes we have and we can see we have four nodes 9v 9v which is for default.user and then we have two um documents created by the pixelity email which start with the user id of pg as you can see in here and they they have full access to their own documents so now this user you can actually go and delete this document for instance another first note so he can go and say okay i want to delete this note so boom and you can see it just immediately got deleted from firebase as well so they have full access to their own notes but they have absolutely no access to anybody else's notes alright so that's working fantastically if that's even a word fantastically so the next thing we need to do now that we fix this is to go ahead and update the build number in our pop spec yaml file so now i'll show you this let's go to visual studio code to our code right here and then say pop spec um camel and you'll see on top of this file somewhere around here we have this version at the moment is one zero zero plus one but what we want to do in here is just is to say it's one one zero plus one so we're updating our build number in here as well okay so after doing that since it's such a big change you could perhaps look at your terminal and see and do a git status and you can see by updating that build number in here um it didn't immediately update the build number for our application because had it done that it should have also been updated for our ios application in the info plist file so that unfortunately wasn't updated and because of this it's probably a good idea to issue flutter clean so i'm going to bring the code like that let's just say flutter clean okay that's gonna do its work and let's say flutter pop get that and all right that's doing is we're going to say git status let's have a look at our status and there's still nothing changed so let's just say flutter run ios and see if that's gonna listen okay flutter run because that's our default target at the moment is an ios simulator so maybe flutter rom will just accept multiple devices found all right show us the list of devices please perhaps it's having oh now it found it please choose one okay i want to choose the iphone 13 pro so i'm gonna choose um iphone 13 pro number two in here okay so now it's gonna build the project with xcode build and in my experience these days xcode build has been it's just horribly slow so i'm basically gonna stay quiet now let it do its work and when it's done we will continue with the video all right as i suspected this process actually took a very long time and i think we could actually see in here that the xcode build took 164 seconds it is well i'm not going to go into that it's a long time um so let's have a look now if the version was actually updated correctly so i'm going to go another into another shell in here and let's say git status and i still don't see any info plist files have been getting changed on the ios side so i'm just gonna be curious here and then go to the ios file in here and have a look at the xcode workspace and let's have a look at the version in here well the version does seem to have been updated so it's 1 1 0 that's exactly what we specified in our pop spec yaml so that's you making sure that this file is updated and if you don't have xcode so if you're for instance running on linux ubuntu or something and you want to still check whether the version number was updated for the ios application you can always do that by opening up this file info plist inside ios runner and then you can have i believe you could have a look at your flutter build number in here and let's see if flutter build number is set somewhere that one that one i don't actually see the flutter build number being set anywhere so if we search for one one zero actually let's search for one one zero in the entire application and the only thing i can see in here are like some of our pop specs and one one zero in here so unfortunately that's not gonna work so i don't really know the magic behind how the flutter team has actually injected that 110 into it's probably some sort of a build variable so if you want to get into details about that perhaps we could just open xcode and have a look at that application let's go in here into build settings and have a look at the version um and see if there's any one one zero in here flutter build name exactly so that's that's how they're injecting it they have a user defined variable called slots are built and flutter build the name is then being injected for our info p list so if you go here you can see oh this is flutter build number so yeah but anyway it's this this must be a variable that the flutter team has injected into the xcode build somehow all right but bringing up xcode could confirm that the version number is set to 110 correctly so that's all we needed to do then the next step for this chapter for us is to make a build and send it to apple this time so not this time we did it the previous time as well we sent it to apple so what i'm going to do is i need to bring up xcode again i shouldn't have closed it maybe let's go in here and while we're in there we could just go and say we're building for any ios device and then i'm just going to say product archive as we've done in the previous chapters as well so let it do its work okay now our build has been um created by xcode and in here it's very important that you actually check that the version number in here corresponds to the version number that you've created in app store connect and just a reminder in app store connect if you go back there you can see that the version that we prepared is 110 and that's why i said in the beginning of this chapter it's actually important for you to follow the same versioning that i'm doing in in the current chapter so let's say 110 and i'm going to say distribute to apple or distribute app upload and let's go in here analyzing app version fetching app store configuration and i'm going to uncheck manage version and build number because i want flutter to be able to do that and then i'm going to choose the production profile that we've created for application press the next button in here as well and then depending on your network connection and your and different configurations that you have for your network this process could actually take a very very long time previously when i tried this even even though i'm on a fiber optic net network connection with a thousand upload a thousand download it still took about 30 minutes for a simple application to be sent to apple and it was literally stuck in this requesting app information for more than 20 minutes so that's an unfortunate fact that we just have to accept and let it do its work and i will see you then once it's finally sent the application to apple all right so now i can see that our application has been submitted to apple and i have to confess that this time it took only about a minute for this process to go through so that was very fast much much faster than the previous chapters we'd have to submit our application which took upwards of 30 minutes for me so now that it's done after you've done this you will receive an email from apple that kind of looks like this if i can bring it to the screen it will look like this and it will tell you that the following build has completed processing only after this email has been sent you can go to app store connect and go and we also have to fix our missing compliance so let's just say manage and say use encryption no start internal testing after you've done that you need to go to the app store how do you say tab and in that tab let's just select a new bill and it's our 110 build and i'm going to say done in there okay after you've done that you can press the save button and then you can submit your application fresh to apple so that then in turn concludes the submission of our app to app store and um if there's any complications with this application like if apple for some reason can't register a user or something they're going to send you an email telling you about that so then you need to go through that process and help the app store review team in order to get started with your application but if you remember from the previous chapters we've actually left some information in there like review information and told the review team how to register for a user in our application so that information should be sufficient for them to understand how to use the app fantastic we're done with the origin with the submission of our ios app to app store so as usual since we've now changed our code let's go into visual studio code and i'm going to close all these tabs because it's just extremely populated on my screen get rid of the explorer and go to my terminal in here and have a look at art status and i can see there's only two files changed so i'm going to add them and let's commit as step 30 as you can see at the bottom of the screen okay so if you look at our logs we have step 29 and then we have step 30 so i'm going to say git push that's going to push our commit and less than a tag v so step 30 and let's just say get push tags so that is done now and our tag of 30 is also sent to a github what we need to do now as usual is tradition where we talk about what we need to discuss in the upcoming chapters and in the next chapter we're going to talk about sending our app also to google play store we've done it for ios we have to do the same process for google play store so get some refreshments if you want to and i'll see you in the next chapter hello everyone and welcome to chapter 50 of the slotted course in previous chapters we've been working quite a lot with submitting our application for the ios app store using app store connect and in this chapter we're going to focus on doing the same thing but for google and play store so whereas you have app store and at the back of app store you have the um app store connect which allows you as a developer to go and interact with the your product that's going to be submitted to the app store google has something similar for your product for your android app in this case our flutter application to be available in the google play store which is where users download your applications you you as a developer will have to go to the google play console so we're going to take care of that and for that we're going to create something called an app bundle where whereas if you remember when we created our ios application we went to xcode and archive our application and that created something called an xc archive file and that was kind of like a zip file and all your files were all your binaries at least all your like linked libraries all your pods the application itself binary was signed with your production certificate and profile an app bundle for your um android devices as well is a signed bundle so it is the equivalent of your um xc archive kind of and we're going to take care of that as well soon in this chapter and we have a um i mean there's something that i i actually prefer this but i didn't want to mention it before because we were so close to actually raising our ios application we have to make just some small adjustments to our code as well as you'll soon see when we start for instance working with taking screenshots of our android of our flutter app running on various android devices and that's um a scrolling issue that we have generally on our screens where we display the keyboard those screens are um login view and i believe there's register view and where else do we display a keyword i believe we also log in register for a got password view because we asked the user for her email address there as well and also one year for instance um actually we don't have the problem on the edit notes view so that's not a problem so we have this problem in verify email view login view register view and forgot password view so um actually verify email view you could argue that yeah it's it's not a problem but so the issue that we have at the moment is that imagine that your application application is being run on a very small screen and um and then the user for instance has a very very small screen and then they're on the login view and then we displayed the keyboard where at where for instance they tap on the email field and they try to write their email and then the keyboard pops up blocking like half the screen and depending on the size of the screen the rest of the half that is remaining might not actually be able to display the entire contents of your view so this is a little problem and we have to fix it but it is so simple to fix and you may then decide to say well the ios application we've done already is sent to apple it's um it's already accepted and i'm going to release it and you could definitely do that so it's actually good practice if you want to release your is application as is just go ahead and do that and then you can do a patch later and release another application to fix that issue and i think the more you release applications the better because then you learn the process of updating things and sending release notes etc it's just good practice to do that quite often so let's go ahead now and talk a little bit about the documentation for creating an app bundle so i'll bring it up here and it's as you can see at the bottom of the screen it's in distribute console and um there's a lot of documentation here that you can go and read more about it so i thought just to um explain like the google play console in here a little bit to you so that you can sign in here and then you can read more about all these topics so i think it's just a good url for you to um bookmark if you want to be able to release your application in the future as well with google and play store otherwise if you're like me and you sometimes just want to jump into things you could start by um logging into google play console so let me bring you to the next url as you can see the url is played at google.com console about so i'm just gonna say um play.google.com slash console slash out if i can spell and that's our google play console okay and i'm just going to log in here with my a user account and i have this user account here which i can log in with let's see if i can log in successfully with that all right and then it says choose developer again and if you haven't done this before you may have to go and create a developer account first but i but in the beginning of this chapter we talked quite a lot about creating a developer account both for ios and android so i'm assuming you've already done that but if you haven't you can go and create a developer account it is free you don't have to pay for anything so just go ahead and create your developer account so now here i'm going to choose my developer account and just go in here okay so here's my google play console as you can see in here this is the console url for me at least and what we need to do in here is to go ahead and create an app so let's go ahead as you can see at the bottom of the screen let's go ahead and tap on create app in here and now in here it's asking us for some information um and also i just saw that i have a little um ipo in my action so i'll bring the right caption up in here and you'll see that we have to go through these steps in order to create our application all right so i'm gonna go in here and let's just say my awesome notes the default language let's just leave it as english us and and it asks you is it an app or a game then we're gonna say it's an application and it's a free application and and and we're going to say it it meets the developer policies and accept us export laws okay and then we create the application this may take some time okay so what we need to do now is to go through um app access in here so i'm going to bring up the caption so we need to go through let's see if you can actually find the provided information about your app and as you can see it's right here provide information about your app and set up your store listening okay so i'm gonna have a look at that and these are the things you have to go through and we're actually gonna go through this together to in order to be able to create a listing for your application so it's a good check checklist basically um and i have to say i mean i'm more used to the app store connect interface it's a little bit like less cluttered i find google play console a little bit more cluttered to be honest with you and things are just there are so much in your face but once you get used to it i think you'll understand the purpose and and then you'll just as as long as you know where to find things so in the dashboard and for your application just scroll down to set up your app provide information here about your app instead of your store listing and let's go to app access and set that up okay and then here is asking us okay is there any restricted content that we're going to say all functionalities available without special access press the save button and you can see for instance i saved it and now i have to manually go back to the dashboard it could have just saved it and sent me back but no it doesn't do that so app access is now crossed out as you can see all right let's go to the ad section so for the ads we're gonna say no my app does not contain ads okay press the save button and then dashboard button so that's for ads and let's go ahead and take care of content rating and this is kind of like what we have to do for app store connect as well in order to for instance say our application doesn't contain violence it doesn't contain mature content etc so let's go to content rating and say start questionnaire and let's just fill in our email address so in here i'm just gonna provide if i can spell support at a pixelity i have some problems right now uh support at pixelity ab.sc and i believe yeah that's my website so um so i think that's that's the email i've been using in app store connect as well so uh let me also just double check that in my notes so i'm gonna bring this into a separate website just i'm gonna check this in my website um and i think the it is actually so i'm not using this anymore so let's just pick some of the appointments and here you just have to enter your own email so don't enter my email here so this is in case they need as you can see if in case they need to contact you so the category of our application we say all other app types because it's not a game or social or a communication application so next does the app contain any rating ratings relevant content downloaded as part of the app package code or assets no and user accountant does the app natively allow users to interact or exchange content with other users through the voice communication text no then let's say online content does the app feature promote content that isn't part of the initial app download but can be accessed from the app no promotion or sale of age restricted products no miscellaneous does the app share the user's current and precise physical location nope um does the app allow users to purchase purchase digital goods no is the app a web browser or search engine no is he a primarily a news or educational product no okay so we save this and we go to the next page summary and you can see it says rating of 30 in brazil all ages peggy 3 everyone can use this application rate it for three plus not sure to be honest with you with that three plus um and then we could just say submit all right so that part is done seems like it and then we can we can just go to our dashboard okay and then let's go and take out our target audience and we say in here we choose 13 to 15 16 to 17 18 and over can also use our application okay and this is kind of like something you may decide on your own whether like you you must add a privacy policy target audience inclusion or under 13 and that's why we're not like targeting anybody under 13. and to basically you may say oh my app's only suitable for 18 and plus and that's that's that's completely up to you and you're more than welcome to do that but i think our app is suitable even for 13 or even maybe less a 13 is quite a basically like the sweet spot i would say yeah because if you go lower than that then you'll have to provide like your privacy policy for those specific targets so we're not gonna do that and then we're gonna press the next button and let's have a look in here what's asking us to do appeal to children could your store listing unintentionally appear to children and we say yes because um we may not want this app to be appearing for children but it may appear nonetheless so let's just say yes there and in here you can see the target group is 13 to 18. so that's great now we saved it and let's go back to our dashboard and you can see here a target audience is also done so let's go to the new section in here news app is our app and news app and we say no all right and then we save and go back and you can see that the news app stuff is done so let's now have a look at this covet 19 contact application and we say um my app is not a publicly available code with 19 contact tracing or status app so save it and we say go back to dashboard so that part of the application process is also done now we have to fill in the data safety stuff so let's go through all of these and and this might take some time but that's okay does your app collector share any of the required user data types required does your app collect or share any of the required collect required user data types what do they mean by required personal information yeah we will collect email addresses so yes of course so let's just say yes and let's remove that is all of the user data collected about your app encrypted in transit yes and that's because we're using firebase and that's using https so that's encrypt in transit do you provide a way for users to request that their data is deleted no we don't do that and i actually believe that it will be really good if you did that so if you are curious about this and if you want to allow the user for instance to be able to do that you could you could check that out and see how you can request their data to be deleted you can create a separate view for that for instance and from there you can you can basically make an api call to firebase and delete this user so you could do that if you want to okay and i may actually provide a chapter for that i don't know but at the moment we say no data types okay and let's have a look in here this may take a quite a long time so let's have a look um data types you must select any user data that's are collected okay we're not doing um location personal information and we're collecting email personal identifier that relates to an identifiable person for example an account id account number or account name yeah personal identifiers yeah definitely um and other personal info we're not collecting so we only have a user id and an email address and that's it and we're not even asking for their names so financial info no health no messages let's see what messages uh entails in here where is it where do you go here messages emails no photos and videos audio files files and documents um files and docs a user's files or documents or any information about a user's files or documents for example file names yes because we're storing actually their files their notes so app activity no contacts calendar no web browsing no app info and performance no device or other identifiers no so let's just then press next there and not started so let's have a look at start this email process in here and we say select all that apply is this data collected shared or both it's only collected okay and data collected in this way must still be disclosed but will not be shown to users on your store listing is this data processed ephemerally process family means that the data is only stored in memory and is retained for no longer than necessary so no it is it is not stored only in the memory so and we say is this data required for your application and in this case i believe that we're talking about email address and yes this data is required so i'm just going to say yes it's required why is the user data collected it's for app functionality okay so um use for the setup and management of user accounts actually yeah account management so let's just say account management so um and then press the save button so now we've submitted the email address and while we're why we're using that so let's go to personal identifiers now and start that process so we say we are only collecting that and because it's a user id and we're not processing it ephemerally i think that's how it's pronounced and we say the data collection is required and we say um it is used for app functionality okay because we're using the user identifier remember when we store their notes so it's more for app functionality than it is for registration so that's why we do that and that is completed now so let's go to files and docs and have a look at this process files and docs and say it is only collected but it is not shared remember we are not sharing the user's data even though we added that sharing sheet for the user to share their own information with someone else but then that is their choice it is not something that we are doing okay is it then is this data processed ephemerally then we say no and again i don't know if that's the correct pronunciation and then is this data required for your app and remember we're talking about files and docs users can choose whether this data is collected okay because it is not something that we force them to do okay and why is this data collected then we say it is for advertising personalization should i recommend it no account management no so it is app functionality we would say and we save it and that's it so after you've done that we can just go to the next screen and have a look at this how it looks like you can actually read about all the information that you entered in here so um and in here you can see at the bottom of the screen says provide a link to your privacy policy and and i have already a privacy policy so i've um i believe i have it in privacy policy text so i'm gonna copy that and go to privacy policy in here actually leave and discard stay um so we may have to actually provide that privacy policy i haven't yet done that but we will have to do that and on the privacy policy page so yes we need to we need to actually do that so let's go ahead to um i actually don't want let's save this as draft and go here and then enter the privacy policy in here and i'm just going to say https let's just make sure it's https yes and save that okay then i'm going to go back to the dashboard in here where we were for data safety we were at the end of this so let's go to uh next um next next next at the bottom of this now we have our privacy policy so now we can save this and let's see if there's anything that we have to do in order to actually submit it so it doesn't seem like it so it is saved successfully so if we go back to the dashboard and then have a look at our data safety now we should be able to see that it is crossed out so that's fantastic so um data safety is done and now we have to have a look at this app category and provide contact details okay so let's go in here to app category and we say it is an app and it's category let's just say utilities if they're if one exists in here um let's just say it is a what should we say communication education events food house library blah blah medical news personalization productivity perhaps okay and then tags let's just say um oh this is horrendous okay um let's just say a note notebook yeah let's just keep that okay and you can choose more tags if you want to and after that is done let's see store listing contact details and email address i'm just going to say support app pixelity.se phone number and i'm going to enter some phone number in here okay just a fake phone number for now and https pixelity.se external marketing and you may choose to advertise your application outside of google play if you want to and that's okay perhaps and um before i save this i'm going to bring the screen to another screen and actually enter my real phone number okay so i'm going to do that here let's see if i can manage to do that it doesn't really seem to like the fact that i dragged it to another screen now it likes it okay so let me see um uh it really doesn't like that i'm dragging it to my ipad so i'm gonna bring it to my macintosh yes and so all i'm doing here is just to enter that information so let me bring it up again and then let's see if you can press the save button okay so all i did is just move the screen to another physical screen enter my real phone number and that was it so oops stay safe your changes couldn't be saved why not let me go and see if i enter a valid oh i entered my phone number incorrectly so i'm just gonna save it and scroll to the top of the screen bring it back up and then let's go to all apps okay oops i want to go back to my app here so in here we're done with the select app category so that's fantastic now it's the juicy part we have to set up our store listing so um this is also actually going to be quite a an important part of the setup process so this may actually take some time but that's okay and we're gonna take care of that in due time so now we have to look at setting up our store listening and the store listening um is one of the absolute core components or and the core things we have to do in order to be able to release our applications so let's go to set up your store listing in here and let's put a short description and say store your notes securely okay and a full description with this application and you can store your notes in the cloud okay so and also i strongly suggest that you write some proper description for these things and it is also very important if you remember that we used an icon for our application and that icon we brought it from stock io so if you go in here stock io and we use the sticky note icon so it is important that in your store description in both ios and android you just say um app icon provided by and just give some attribution to that okay so it's very very important that you read these things and also give attributions where attributions are due so now we come to the application icon section and you can see in here that says the application icon should be five twelve by five twelve and we don't have that unfortunately at the moment what we have is a thousand twenty four by thousand twenty four so if we go back to our downloads for instance in here you'll see that we downloaded our app icons in one of the earlier chapters and we have this app store image in here which i believe is thousand twenty four thousand twenty four at the moment so what i'm gonna do is i'm gonna duplicate this file command d on my macintosh on windows and linux you may have to do something else and if you have for instance paint and paint plus plus it's called paint.net or something on windows you can also resize your image but all you need to do is just in your host operating system you need to make sure that this image is 512512 so on the mac i'm just going to click on here it open on a separate screen and then i'm going to go to tools and say adjust size and i'm just going to say it is 5 12 5 12 okay these are the guidelines so in here i'm just going to drop that file right there okay okay so that's for your application icon that's 5 12 5 12. now we also need a it's a required feel as you can see it is marked with an asterisk in here and it's a future graphing and future graphic is something that a google play store can sometimes use in for instance if your application is featured on play store um and they are going to use this image in order to to basically um do an advertisement for applications so there are guidelines for this and it should be you can see it should be 1024x500 and since we don't have that we are going to use our application icon in order to create that future image so what i think we should do is just to open figma perhaps and after our figma document is open what we can do in here is to go and create a little rectangle which was 1024x500 i believe the guidelines were telling us to create it by so 1024 by 500 so i'm going to select this rectangle and i say its width is 1024 by and then height is 500 and what i like to do is to go my trusty color palette which is from a tokyo night let's go to tokyo knight in here in github as we've seen in previous chapters i'm going to go scroll down a little bit here and say that i have i want the editor background color so it's 2428 3b and then i'm going to copy that close the tab come here to figma and change the fill color of this layer to that so we're going to use this as our background and what i'm going to do is i'm going to go to our downloads folder and grab that app icon png 1024024 which we've downloaded in one of the previous chapters so i'm gonna bring it in here then it is huge i'm gonna hold down the shift key and then resize this proportionally so kind of reset it to something like this okay so i'm gonna place it in the middle now i'm gonna change the name of this to bg change the name of this to icon by double clicking on it and then i'm gonna create a text field in here and save my awesome notes and let's bring these into three separate lines like that and let's also make sure that the fill color of this is white also ensure as you can see like mine it is right aligned then i'm gonna place it somewhere here okay in the middle as well and perhaps we could even increase the size of the font so let's see what we have here we have about 200 let's say 120 and it is a little bit bigger a little bit bolder in your face kind of stuff so and this is our text so this is our text what i'm going to do in here then is i'm going to um basically take these like bg icon and text and then duplicate this bg in here because this is going to be our mask i'm going to grab grab it and bring it at the bottom then i'm going to right click it and say use as mask and now it has its own group then i'm going to grab all of these three layers and then drag them here and now you can see that that mask is basically masking off this entire content so it's masking off our icon as well so it looks pretty good to me it's kind of proportional it's nice so then you can click on this and then in figma go to the bottom so if i change the um in here so you can see better perhaps then scroll so make sure your mask group is selected then go to export and then we're gonna export it as one x and then that is exported now so now we have our image looking like this and it is 1024x500 so we can go to uh our play console google play console and right where we have to uh throw this feature graphic i'm going to go to downloads and the image that we just downloaded which is right here i'm gonna just drop it in there so then that is working fine as well and then i'm gonna save my changes and something is wrong with our changes some languages have errors okay that's probably because we haven't really uploaded any screenshots yet and we're gonna take care of that soon so it is a little bit um strange that it doesn't let me just let me save my changes as a draft i have to save this entire screen and since i haven't entered some of the information in the screen which is required it's not allowing me to actually save it so but we're gonna take care of that soon so um what we need to do in here is to ensure that we're first running our latest application on the correct phone as well so let's see in here i'm going to bring our source code in here and then i'm going to say select the device and then i'm going to choose my android phone all right so that's that then i'm going to actually grab my android phone let's see if i can do it without causing too much problem here on the screen like that and authenticated great make sure it is connected to wi-fi as well fantastic so my android phone is now set up and let's then go ahead in our source code let me change some screen layout in here in our source code then i'm going to go to main dark file if i can spell dart file and in here in our terminal i have two terminals so one i usually dedicate here to um scr cpy so i'm just going to say scr cpy and that's going to bring up the android phone up right there and since we've selected that we can now just say run without debugging so the goal in here is to run the application on this particular android phone and have sdrcpy take screenshots for us as you'll soon see so there's a really good command called adb and adb is like the low level and low level android debugger and by using adb you can actually communicate with your you know for instance your emulators android emulators and your android phones as we have here so if you don't have adb you will actually have to install it so if i say which adb on my computer you can see that it says it's homebrew bin adb basically telling you that i've installed adb using homebrew if you haven't a if you don't have adb on your computer you may need to install it if if what you're also doing is following along with the steps that i'm providing you meaning that you're taking trying to take a screenshot with from an actual device that is connected to your computer okay so i can see now that our application is running in scr cpy looking like this so what we could do is to issue the command as you saw so let's just go ahead and say um adb exec exec out screen cap key and then we save it into for instance file1.png and if i have a look in visual studio code you'll soon see now there is a file stored here file1png and that is that file with the screenshot of our application and then we can go to another screen for instance the i forgot my password screen in here and we could also send our keyboard down kind of look like this and then we can issue another one file to png so that's stored as well let's go to the registration screen and send the keyboard down and then let's say file three png and also sending the keyboard down or up or leaving it up it is it is a it is a taste thing it is completely up to you how you want to do it okay so in here i'm going to go here vandal mp and actually log in with a real user and go to the main screen of the application i'm gonna take file for png and then i'm going to go to one of my notes in here with the keyboard up perhaps in this case and then say file five png okay and then i'm gonna say open so i'll see all my png files in here then i'm going to take those files and bring them to desktop so they're not polluting the workspace here in visual studio code let's go back in here and you can see that you can just drop drop two phone or tablet screenshots in there so let's go ahead to my desktop folder where i stored all those screenshots and just drop all those images in here okay and i can see them populated here i'm gonna grab the login screen and see if it can actually bring it first and unfortunately here it's not allowing me to drop things at the right order so unfortunately i have to delete them and like drop them at the right order so file one first and then i have to upload file too so it is a little bit um strange that it doesn't let me re rearrange these images but perhaps there is a functionality for that that i don't know about so let's then say file four and then we have to upload file five as well okay so that's there as well um okay so that's that then what we need to take care of now is to create a five inch tablet and since i don't have a five inch tablet here sitting around as a physical device then we have to go and create one so if we look at um here visual studio code and go to flutter select device you'll see that there are various um basic um tablets that i've created with my device manager with android studio so if you have android studio you can always open it and android studio um oh oh it did open it anyway so it's right here you can always go i believe into um avd manager which is the virtual device manager and then create your virtual device as you can see you need to create a file is this seven inch and a 10.1 inch tablet because we're going to take screenshots with these so what i'm going to do actually is to launch both of these tablets so that they're ready to go when we need them so that's the first tablet and i'm actually going to turn it around so it is in the portrait mode so that's that one and then i'm also going to ask avd manager here to run a second tablet in here and that was extremely fast i saw i don't even know how it did that how could it run this tablet so fast a little bit scary to be honest so now that's sitting there um let's see if it's gonna do its work correctly though i can see the seven inch tablet is not doing so well let's see if i can close it and i'm gonna say yes close so perhaps i should have i'm going to shut this one down and don't know if we're going to actually be better off first running the 7-inch tablet and see if that is successful maybe something happened in the processing of the 10 inch as well as the 7 inch i don't really know it is completely up to the device manager here and i can see that this device isn't really doing so well so i press the power button on it here and i can see now it is running so i'm going to press the home button and um orientation isn't really working so well here so i can see that now maybe it's working a little bit better so let's just leave it at that so that's the seven inch display and it is up and running then what i'm going to do and the flutter daemon has terminated that's completely fine reload it then what we're going to do is to say select device in here flutter select the vibe and that's probably because the flutter demon actually crashed on us here so i'm gonna try one more time and if it doesn't work then i'm going to quit visual studio code so let me start visual studio code and fresh okay now that visual studio started fresh let's just try again and say flutter select device and this time i'm going to choose a 7-inch android tablet then i'm going to say run without debugging so let's see if we're going to have any success running this application in this tablet and if gradle build is working well for us today then it's going to allow us to do lse performing stream install failed to install launching application and sdk g phone 64 rm64 so there could be some problem with this android tablet in here so i'm going to close that and i'm going to go back to android studio if i can't find it somewhere here let's see android studio okay it's running now and let's go in here then i'm going to go to avd manager and let's have a look if we can close these and kill these two tablets completely like that like that and while i'm at it i'm also going to kill this one so i don't have any use for that so i'm going to create a new virtual device then i'm going to say excuse me a tablet that is nexus 7 and 7 inch display something like this that is fine and it's thousand 200 by nineteen twenty so what is required here from us it says uh seven inch tablet screenshots okay that's fantastic so it doesn't have specific size requirements and then i'm gonna press next on s is absolutely fine that is fine as well on portrait and then i'm going to say finish then let's see if he can run this emulator on this computer and if everything goes fine we're going to see the welcome screen here i can see google's logo so that's a great sign always and i'm going to keep the screen here just in case and while that is doing its work we're going to go back to flutter and i can see the emulator is up now and i'm going to say select device and i'm going to choose it here let's then say run run without debugging and see hopefully this time we have better luck in running that application in the given emulator so let's see wow that went really fast actually it went surprisingly fast so now it's running in there and i can see our application running in the emulator so what we need to do in here is to actually take some screenshots so um when we need all you see here actually we all have to provide 7-inch tablet screenshots and we also have to fix the 10-inch tablet screenshot but what i want to mention is depending on the size of the screen at the moment you can see everything is working fine there's not a problem you can go to register screen i also forgot my password and all of these are working quite fine however we have a scrolling problem and i can see in here that the seven inch display i've mentioned at the bottom of the screen that the seven inch display could actually block the view and that could be for instance because um now in in this case is not actually blocking the view but if you had a smaller screen it could block the view in that this screen as you can see is not scrollable so if you had a smaller screen then this keyboard could pop on top of the content that you have in here blocking the content so what we need to do before we start taking some screenshots from our android um tablet let's go and fix these things up let's first go to our verify email view in our application oops i press the launch button again by mistake sorry about that i'm going to stop this let's go to and verify email view and you'll see in the code that the verify email view state at the moment's return is scaffold and it has a column in order for this column to be vertically scrollable all you have to do is just wrap it with a widget and just say single child world view as the notes indicate at the bottom of the screen okay so that's the scrolling down for that let's now go to the login view so login view and wrap the entire content in here in this column and let's say wrap it with a widget okay and i'm going to say single child scroll view just like that okay and i changed the screen layout a little bit so you see the code better let's then go to our register view as well so register view and on top of the screen we have the scaffold and a column so let's also in this column say wrap it with a widget of single child scroll view alright and last but not least we're gonna go to our forgot password view and have a look at how we're creating the screen we have a scaffold padding column just like a standard we've done in other places as well wrap with widget in a single child scroll view all right so that's that now that we've done that we're actually ready to launch this application again so select device to nexus and then i'm going to say run without debugging all right so what we need to do now is to use adb again the low level debugger for android but this time we want to take screenshots of an emulator as you saw in the previous uh section when we talked about taking screenshots of an actual android phone running in scr cpy we had to use adb as well but we didn't have to tell it that it is an emulator as you can see at the bottom of the screen now if you specify an e flag to adb then that indicates the adb that you want to take a screenshot of an emulator okay so here's that device running excuse me our application and what we need to do now is to go to command line and let me just do some reshuffling on the screen and this is our scrcpy and i'm gonna just do some screen shuffling here so get rid of this let's go to terminal okay so let's issue the command as you can see at the bottom of the screen so i'm gonna do like this and uh like that so adb exit out but before that i'm just gonna say dash e and screen cap e and then let's say file one png all right so and if i now go to the project structure i can see there is a file called file one png and it is a screenshot from our emulator okay so i'm gonna re do the same thing i'm gonna go to forgot my password screen and um let's get up and get rid of the keyboard in here and let's remove that space that i just entered and then take the second screenshot as file to png and then let's go to the login page and the register page get rid of this keyboard file free png okay so now that we have that oops i'm going to i press the back button i'm going to log into our application with my email address and our horrible password of foo barb ads now we're in the application let's take a fourth screenshot called file for png and in here while this is up with the keyboard perhaps as well let's see and then take screen shot 5 or file 5 png so now we have 5 screenshots from our 7 inch display as well let's excuse me let's go and collect those screenshots file one two five and then i'm gonna delete the ones on desktop and just cut and paste the ones from our application then let's go to um our google play console in here in the seven inch display i'm gonna drop these one by one so drop the file one in here and then let's drop file two right after that and then we can say file three four and five so i uh so that you know how um i'm thinking about the ordering of the screenshots okay so that's file four and then we have file five right there and what we need to do is we need to basically do the same thing for as a 10 inch display as you can see here it says 10 inch tablet screenshot so let's go again now we can close this emulator that is right there then we can go back to android studio so if i can find android studio here okay let's go to avd manager and in here we're going to create a new virtual device in this case it's going gonna say tablet and in a nexus 10 is a 10 inch display i'm going to press next and then sdk s that's fine as well and just run it ooh landscape not sure about that but that's that may be fine but you know what i'm actually going to delete it and create a new one because we had some problem before with the landscape mode so i'm going to say nexus 10 again next next portrait and then finish okay so hopefully this starts it in the portrait mode so then i'm gonna press the play button right there and unfortunately it started in the landscape mode but that's okay hopefully we're gonna be able to rotate it around and i can see now it is running hopefully uh so like that and we should see now the home screen let's see if we can rotate this uh and unfortunately it doesn't actually rotate so i want to see if there's any properties in here that allows us to change the display from landscape to portrait so snapshots recording settings enabled light proxy advanced show window frame nope nothing in there that allows us to change this device from um directional pad no it doesn't change the display from landscape to portrait and i am now basically trying anything i can so even if i go to chrome in here for instance and say no thanks and then if i rotate this i can see that it's unfortunately not rotating the actual application so we might then have to take a screenshot in landscape mode so let's see if if you can actually do that so if there's anybody out there who knows how to fix this issue i'd be grateful to also know because at the moment even doing the command right and left it's not listening to my commands it's not basically rotating so how about this icon um well that didn't help so so much to be honest with you so um it didn't really i mean i can go here and then here oh now it's portrait okay i did something so i just clicked on a little icon on the top left after rotating so it rotated to portrait so that was just pure luck let's go to visual studio code and say command shift p on a macintosh or ctrl shift p in linux and windows and save flash or select device choose our 10 inch display then i'm going to say run run without debugging and if everything is working correctly and gradle's working in our favor then then the gradle task is going to go by really fast and i'm very grateful actually for that to be honest so gradle is working a lot better now than xcode build process so here's our application and displayed on a 10 inch display and let's go ahead and start taking some screenshots so i'm going to go to terminal here and then start taking screenshots of file one in the login view then let's go to forgot password and say file two i'm gonna get rid of the keyboard and take the screenshot without the keyboard i'm gonna go here to the register view get rid of the keyboard and then say file three so that's that let's not log in with a user um like this and say foobar baz log in with that user oh wrong credentials okay uh foo barbaz login and after logging in we're going to take another screenshot which is our screenshot 4 and then we're going to take another screenshot with the keyboard and for our um file 5. all right so that is also that then i'm going to open the current folder i can see five screenshots in here go to my desktop get rid of the old ones and paste the new ones in there okay now that we have those we can clean and remove this emulator we don't have it and i'm also going to close avd i can see it's already closed so let's go back to um our play store in here so and play store um console so i'm gonna upload this new um png file file one then file two for the ten inch tablet so all of these five screenshots are for the ten inch tablet three and then we're gonna go to four here and then last but not least we're gonna upload screenshot five and then right after the upload is done i'm just going to delete all those files to keep my desktop clean so after doing that let's just then save this and now you can see it says your changes have been saved fantastic so now that is done and we need to create a release app so if i just bring my notes up a little bit here fantastic so what we need to do we need to have a look at a little url here as you can see at the bottom of the screen it's called docslatter dev deployment android it is a very important document and here i strongly suggest anybody who's trying to create a release application to go through this it has information for windows and macintosh and linux users and these commands are absolutely um full of value so you may have to google these otherwise around but this document has really put all of that together in the same place so as you can see in here the first thing that we need to do is to create a signing key for our application and you need to follow these um commands in here that have been created for you so you can see and if i bring a terminal up so if i say terminal and i'll bring it up here and if i go to this folder dot android on my computer like this and i already have some keys as you can see in here so i have some keys already set up but in order for us to actually um be able to follow along with this and guide we need to go and create these keys for us as well okay so what i'm going to do is i'm going to do let's see if i can bring up the command for you as you can see at the bottom of the screen so i'm going to actually copy that command that i provided for you at the bottom of the screen okay so and i'm going to go to terminal and um let's just go to desktop for instance and then i'm going to issue that command exactly as you can see at the bottom of the screen so let's see what happens in here now it says enter a key store password so this is a password that you need to then provide inside a property file i'll tell you soon about it so remember this password up until this point for this course we've been using foobar baz as a password is an absolutely horrible password so please don't use that but since we've used it consistently in this course and since the password in this sense has no meaning for this course i'm just going to say foo bar pass but please don't use a password as weak as that so let's say foo barbaz and let's see what it said java as a keystore was tampered with or password was incorrect so um it this could perhaps be because i'm actually trying to create an upload key store like this and i already have one from before so what i'm going to do is to actually delete this file so i'm going to say remove that file okay upload keystore like that and i'm going to issue this command again and i'm going to say foo bar house and fubarba so if you if you've already had a key store from before then you could just use it but i'm assuming that you didn't have one however when i did issue this command i already had one so chances are you didn't have a keystore from before you didn't you didn't have to delete it but in my case i actually have to delete it first and then issue the command that you can see in the caption at the bottom of the screen so what is your first and last name i'm just going to save and i have andy poor okay and your organization unit i'm just going to say development and then name of your organization is pixelity a b okay city or locality okay i can just say stockholm okay and state or okay stockholm again let's see uh two letter country code i'm gonna say s e and it is saying is it correct then i'm gonna press the enter button uh i've already entered all of that maybe i made a mistake in here so let's just say what was the question correct no do i have to type yes i'm just going to say yes so you have to provide yes at the end of that and then what is the same return if same as keystore password yes just enter okay so now it's created a key store for us in here you can see in the android folder upload keystore jks okay so that's very very important now that that has been created what we need to do is to have if you had followed this you can see that what we need to do now is to go to our flutter project in here you see it says go to your flutter project and and go to the android folder and create a file called key dot properties okay so let's go ahead and create that so i'm going to open visual studio code in here and then i'm going to go to cd and let's see where we are at the moment we're in the root folder of our project standard project i'm gonna go to the android folder as it was suggested there and then i'm gonna create a new file as it was called here key dot properties okay so key dot properties like this and then i'm gonna paste that content that was mentioned here as you can see like that so maybe the entire content so i'm just gonna paste it in here okay so it says password for previous step from previous step and we just said fubar bass like that and the key password as well and again that is foo bar bass the key alias we're going to leave it as upload and in here we're going to say the file was stored in let's see if you can get the entire path for this so it's right here so i'm going to copy that path path sorry and then i'm going to delete this information in here and then paste it right there okay so that should be good to go so i'm just gonna double check in my notes as well that that is how we've done it before as well and that seems to be completely fine so then after doing that with an empty line at the end i'm going to close this file and save its contents right there so now if you go to the main folder of your application and say git status then you should see that you have only these things basically committing to your project because your key properties are not going to be committed okay so and that's that's why i'm mentioning here that you always need to make sure that that particular file is not going to be committed with your project into github so you could always go to your git ignore file and actually add that particular file to your ignore so let's just say veeam git ignore not get ignore and in here we're just going to add a new file and say any key.properties file should not be committed and then we do a good status again that our get ignore is changed if you're paranoid like me you will do it like i did all right so after doing that what we need to do is to in fact create basically um sorry we have to update our build gradle for signing and i provide a link which i'm going to go to myself and let's see um if i can find that link myself configure signing in gradle and that is right here uh here and it is telling us exactly what to do it says add the keystore information from your properties file before the android block you see this android block in here so what we need to do is to go to this file in our project android app build gradle so visual studio code let's go to um build.gradle in android app all right so we're there and what did it say that we have to find this section android you see so let's find the android block right there it's just one so right there then let's copy this text as it is mentioned there and paste it right before android okay boom and i'm going to bring it one step back as well so it is um basically formatted correctly okay so that's that part and it says then load the key.properties file into the keystore properties object and that's what this guy is doing okay then what we need to do it says find the build types block so let's go and find that you can see the release we're gonna basically edit that as well so i'm gonna go to my notes as well build gradle uh sorry about that just to ensure that i'm following all the steps correctly and in here it says release to do add your own signing config for the release build signing with the debug key for now so flutter run release works and it says then replace that with this so you just have to grab this information here and just completely replace this build types with that thing that was provided i'm gonna fix the uh indentation a little bit as well so here the key alias password are being read from the correct place and then the release is signed with the release key in here and that is it really so you don't have to do so much more and what we're gonna do now is to as you can see at the bottom of the screen we're gonna do some cleaning up of the um of the build artifact so in your project you need to now go to terminal here as you can see for on my screen so i'm just going to go and say flutter clean okay so like that all right and we're then going to say flutter pub get all right and after doing that we're actually going to um create our app bundle so after doing flutter pop get then you have to issue flutter build app bundle so by issuing this command you can see now it is going to start building your application with griddle using all those properties that you've specified in those various files so there was a lot of work that we have to do but thankfully it's been documented so well that it makes the whole process so much easier had it not been for all those documentation bits and pieces it would have been such a difficult process to go through so let's just wait for this build gradle process to now do its work and all right now you can see that the process has gone through it has created our little app bundle which is this aab file and what we need to do is to be able to then upload this app bundle to google play store so let's go back to our play store and here i'm going to close this close figma and let's now go back to our dashboard in here and you can see my awesome notes and let's see what we have going on in here and what we need to do is to go to our production in here and and then create a new release okay so press the create new new release in there and you can see now it asks you to upload your app bundle so what i'm going to do is to go back to visual studio code and see where this file is located so i'm going to open that folder and i can see the aab here and i'm going to then drag it in here and place it there okay so after this upload is done it may take some time i can see it's 25 megabytes although i'm at a thousand thousand line um fiber optic network in here it's taking like a while to upload i don't know really why but in the release name as you can see it says that well this is not something um that we actually share with anybody so let's just say um first we call it first version okay so and in here for your release notes you will basically copy from a previous release well we don't have that listen here just say um the first version of our app okay and then we can save this information all right so excuse me so now we have that um we have the first version in there okay and that should be it so let's just go to the review release in here and we have one error that's probably because we haven't provided the countries and add at least one country or region and that's fine we're gonna we're gonna add that so let's go and see overview where we have to add these countries if we can't figure it out somehow let's click in there android okay that is fine and um we need to go to under production and all the countries or release as you can see in google play a console under production so i believe we're already under production so if i click under production now we can see countries and regions so let's go in there and say add countries and regions and i believe we could in here hopefully select all countries if you sell such good make sure your price for the countries well can we not sell oh yeah i i saw that if i click here i can select all the countries so let's do that and say add countries and regions and then press the add button fantastic then we're gonna go to our releases and uh here we have this release so let's go to the release dashboard okay that's fine and then i'm gonna press the edit release and i'm gonna press the review release now that we've selected all those countries we have one warning the app bundle contains native code and if you've not uploaded debug symbols okay and these debug symbols is something that i actually encourage you to go read about because these are gonna allow you to see when whenever and if there is any crashes in your application occurring anywhere where your users are using your application so i would really suggest that you do this and upload your d box symbols although that's something that i believe is outside the scope of this course but it should be quite straightforward for you to figure it out and there's link in here that you can read more about it so now we can start the rollout to production and then say rollout and you'll see now this is going to go in review and and google uh cons like at the play console could take some while some time to rel to review the first version of our application some people said it takes upwards of a week and for me it's some sometimes actually taking about eight nine days so depending on what you've done like that your track record from before if you release any applications from before you may actually be able to be placed somewhere first in the queue or maybe last i don't know i don't know their processes so um and that that was really in that was like the releasing of our android application and we went through quite a lot even figma design in the middle of everything so congratulations for going through this together with me since we've changed some code let's go ahead and um actually commits all our changes so i'm going to say good status and make sure that your properties file the key properties file is not added so let's just say git add all and then i'm going to say git commit step 31 and if you have a look at our logs we have step 30 and 31 so let's push those changes to our remote and then i'm going to say get a tag also step 31 okay and get push tags so that was it now you've released your application for ios and android and um this this could perhaps be the last thing that you will um learn about in this course right now as it is if you're one of the early adopters of this course but i'm planning on putting out a lot more videos that i'm going to append to this course with a lot more material so stay tuned and i may actually see you in the next chapter hello everyone and welcome to this chapter in the previous chapters as you've been following along with this course you know that we've created our application and we've also released it to the app store for ios and also google's play store using a play store console and now you will i mean any application or any software is not something that you will do and it's just finished every application has to live on and there will be you will add new functionalities to it and then um you kind of have to keep it alive just as i will keep this course live you'll also have to keep your application alive so one of the things that you might want to add to your application is localization now um if you don't know i mean if you haven't done software development before you may not know what localization is but localization in um short form is the process of you making your application more accessible to other people in different countries than the one for instance that um you live in so up until this point we've been creating our application with a user interface that is mainly in english but you may not be even from england you may not be from australia or us you may just speak the language english and um for instance i live in sweden so the application that we have developed right now isn't really accessible to everyone in sweden even though most people in sweden speak very fluent english however it's not their mother tongue so localization is um the process of making your application more accessible to those people who don't speak the language that you've designed for your user interface and it's not just about the language and the text that you're using it also entails a lot of other and also includes many other things for instance how you present currency and values in your application now we don't have like a shopping basket or anything we don't have an e-commerce application and that we've developed so far so there's nothing for the user to purchase in the application but um if you were developing an application where the user could for instance buy things then your shopping basket would need to for instance present the amount um for um like the product prices in in that person's currency so if you're for instance presenting the ui to a person in sweden that person doesn't expect to see for instance prices in dollars they would expect to see prices in the swedish crown and um or if for instance you're doing this application for someone in england you'd probably want to do with gbp which is the great british pound i think or just pound so localization is a lot more than just changing the text of our application but since our application doesn't have any of those things we're not presenting any dates for instance at the moment we're not presenting any currencies or values like that then for us it in it basically means only changing the text of our application so what we're going to do in this chapter is going to localize our application and we're going to do it in two languages so for english which we've already done so far which is the text that we've provided for the user interface of the application to this point and we're also going to do it in swedish now you don't have to know swedish in order to be able to go through this chapter i'm going to help you with that and there's a github repository for this project that you can just copy and paste the swedish text for instance you don't have to even write swedish at all you don't even have to follow along writing the exact text that i'm writing for instance in swedish you can just put some gibberish in there because all you have to do really is just to understand the concepts of what localization entails for your application how you can do it with flutter and then when it comes to actually localizing your own applications then you can for instance choose um bangladeshi or if you want to choose any language in india for instance or um or do if in pakistan or whatever um language you choose to basically go for so you don't have to really know swedish that's what i'm that's what i'm saying but um also as you can see at the bottom of the screen localization could also be for languages that are not traditionally left right like farsi or um arabic so those languages are written right to left so there will need to be some special considerations made into um code for you if you're trying to support right to left languages like for c and um so for instance a name of a person um you may want to be able for instance if you're presenting a list of famous people that for instance the user can read about those names may not have to necessarily be um presented in arabic names like they're like their spelling doesn't necessarily have to be arabic it could be english but for instance an age of a person like if you were saying bill gates you could write the name in english even though the language of user user interface is arabic but the age of that person if you're presenting then it might need to be translated in like um numerical values that are under understood by whoever speaks that language so um what i'm trying to say is that if you're trying to support right-to-left languages you may have to take into consideration those points that i just mentioned but in this chapter we're not going to do that we're just going to cover english and swedish and those both languages are left to right now let's have a look at the documentation because the documentation for localization of a fluster application is very thorough and i highly suggest that after watching this chapter and learning about it from my perspective i think it is very very important that you actually have a look at the um the official become documentation i'll try to open with a tab in here so um i'll bring it to the screen so you'll see so i'll get rid of that and i'll bring up the screen a little bit like this sorry i have to do some rearrangement so you see the screen better so as you can see here it's an official documentation for accessibility localization and international internationalization and um you'll see some terms sometimes for instance and during internationalization and localization you'll see some terms such as i 18 n and sometimes you'll also see l 10 n and you'll be wondering like what are these things what does it even mean l 10 n and the reason for like what i 18n actually means it is internationalization um and if you look at it internationalizes if i write it the asian like this and then if you take 1 2 3 4 5 6 7 8 9 10 one two three four five six seven eight so 18 total number of characters between i and n so it is known then to write i 18 n just to refer to internationalization and the same thing is true for localization because let's let's bring up for instance visual studio code maybe we can actually see in visual studio code a little bit better um if i bring it up here and i increase the size of the font and if i write enter nationalized international international non-lineation okay and then write localization so that was one two three four five six seven eight nine ten one two three four five six seven eight so it's 18 total and if we look at localization between l and n if you count it one two three four five six seven eight nine ten characters so a lot of people refer to these things as i18n and l10n i18n basically means internationalization and l10n means localization so now you know the reason for that it's just it's just programmers being lazy and trying to like shorten everything as much as they can so now if you see these two terms then you know what they refer to okay so what i was saying basically in the beginning is to please after watching this video go ahead and read the official documentation because it is very important it's very thorough it talks about things that we don't even talk about in this chapter so um i highly recommend that you read this documentation as well okay so that was that and now what we need to do is to basically get started by adding um internationalization localization support to our flutter application so i'm gonna bring bring a visual studio code in here and maybe decrease the size a little bit i'm gonna change the screen layout all right so um this is how we've left our application to this point so what we need to do is i'm just gonna close all the tabs and then i'm going to press command and command p in visual studio to open a file for instance and then we're going to look at our pop spec yaml file so if you go there and what we need to do is to add flutter localizations to our pop special let's have a look in here and you can see and you may be actually wondering why i'm what am i even talking about what is flutter um localizations and i didn't make that up it is basically documented right here let's have a look at it as you can see it says the first thing that we need to do is to go to our pop spec yaml file and add flutter localizations now what this basically does for our application is that it allows our application to be localized and it also adds uh like auto-generated code for our application as you'll soon see so it is a little bit difficult to explain exactly what it does before you've seen the results so what we need to do for now is just to find the dependencies section of our pop specky ammo here and i found it here and what we need to do in as you can see it says you just need to add flutter localizations and i'm going to do that right after flutter okay and a column and then we're going to say sdk flutter all right so that's that and this application at the moment is not running so what i'm gonna do is just to say um select device and then i'm going to use my android phone okay as you follow along with the with the course you know that i prefer personally to have real devices running so right now i have um scr cpy i think somewhere let's see if we can bring it up actually let's go to terminal scr cpy so this is my android telephone and then on the side i also have an actual iphone running here so basically there are two devices and that have our app installed um so an iphone and an android and we're going to work with both of them um so um what we're gonna do is to run our application uh on the android phone for instance i'm gonna say command shift p on uh when on mac and then ctrl shift b on a linux machine or windows and then say select device and i'm going to select this android phone then i'm going to go to the main dart file and then just say run without debugging so let that do its job i'm going to decrease the font a little bit because it's just humongous at the moment so after doing that after adding the pop specky ammo in here we also need to make sure that we follow the as you can see in here it says yeah you have to do these things and we're going to take care of that but what we're also going to do is to add this internationalization package to our application so let me remove that screen from there make sure that our android application is running and this is the state i've left the application i'm logged in at the moment so what i'm going to do is just to log out all right so that up until this point the only thing we did really was to add flutter localization sdk true sorry sdk flutter here then what we need to do is to add the internationalization package to our application okay so let's go and i'm going to open a new terminal in here in visual studio code and change the layout a little bit so you see it better as well like this and let's just go ahead and say flutter pop add intel okay and you can read more about this intel package on popdev so if we for instance go to create a new tab in here and i bring it here and we just say puff.dev and let me increase the size to a little bit more ginormous size and let's just say intl okay and you can see here's the intl package and it is from darkdev so it is actually an official package that you can include in your application and there's documentations about how to use it okay so you can also see how you can for instance um handle date formatting in different languages all right so now we've added that and if i bring this screen like this so you can see the results of adding that package to our application and i can see it says got dependencies all right so that was the result of saying flutter pop at intel fantastic the other thing that we need to do is to go under flutter here in our pop spec if i change the screen layout a little bit more um we need to go as you can see at the bottom of the screen we need to add a generate true under the flutter section and it is right here so this generates true that we add just like this it is um it is very very important basically for how code generation is gonna work so i'm gonna basically have a look here generate and add space here okay so if you add this generate true in here it allows the localization packages and like the localization code that is running in your application to generate to auto generate code for you what i mean by that is as you'll soon see flutter internally uses a file called a file type called marb and these arb files are kind of like key value files and very i mean kind of like json and in the keys um you specify some names for instance you say login screen title and the value would then be the actual value you've translated in that specific language and you will have multiple of these arb files and i think actually i'm going to explain it rb more soon but it stands for application resource bundle but just know that i mean i don't want to go too much into details about arb files right now because there's a section coming up where i'll explain that but what you need to know right now is that this generate true flag under your flutter section in pop special allows the auto generated code to basically hook itself into your project and when you add new keys and values to your arb files as you'll soon see how then up then the code generation will kick in every time you do a hot restart or you run your application fresh and it will go through your arb files and it will generate the keys in inside like a dart um source code for you and this dart source code will be something that you can literally import into your application and like use the keys you added to the json as just like dart code inside your application so this is a lot of talking just like abstract talking but you will soon see exactly how these things work so don't worry about that so what we need to do now is after we've done all this work we need to basically add support for localization into our ios application as you can see at the bottom of the screen in the caption now android works just automatically in that when we start adding localization to our application new languages the android app just completely understands then okay here's a new language i can handle that and i will just refresh my ui in order to display all the values that you entered but ios is a little bit more old-fashioned you have to help it understand that this application actually supports various languages so and i'm actually glad to say that you don't have to have xcode in order to go through this particular section of this chapter but we need to as you can see at the bottom of the screen we have to go to our info plist file and update a special section or create a special section called core foundation bundle localizations okay so let's go ahead and actually take care of that right now so i'm gonna also bring up my notes to ensure that i'm telling you all everything that i plan to tell you see if i can find that section all right so what i'm going to do in here i'm going to close that file i'm also going to close the main dar file and then i'm going to press command p in visual studio code and i'm going to look for a file called info.plist it should be under the ios folder slash runner and in there there's an info p list and if you're curious exactly where that is you will be able to for instance go to terminal and i'm gonna clean the terminal and i'm just gonna say open you can see this is the folder where this entire course source code is based if i say open okay so we're gonna open as you can see in here so this is the source code where we we are at the moment and there is a folder called ios and in there there's a a folder called runner and in there there's a file called info plist so that's where that's the file that we have to open right now okay so i'm going to say command p again and then info plist let's open that and these are like key values as you can see it's it's a strange like p list kind of like an xml format kind of thing but you will need to look for cf bundle localizations in here um and if you don't have cf bundle localizations then you'll have to create it just like in here so as soon as you see this dict which is dictionary let's go ahead and create a new key so let's just say key and we're going to say core foundation bundle localizations okay and then we end the key right there and what you have to do this the value of this key is not just a string but it's actually an array an array meaning that is a list of things it's a list of languages or localizations that your application supports so as you see all the other things in here there they have like these keys and then values but for us we have to do something like this you see there's a key which is cf um bundle localization and localizations and we have to then create an array so let's go up here right after this say array and then we close the array just like that you see this is how they were doing it here as well and then we need to add two strings in here so one string and we close that string and another one okay so because we're supporting english and swedish so every string in your arraylist is gonna then um indicate the language code that your application supports okay so first we're gonna support english and then we're gonna sweet and support swedish and swedish language code is suv because in sweden and sweden itself we don't call the country sweden we call it sevaria and that's what that's where sv comes from but you can also google this and you can like look for localization country codes and you will get to a list on wikipedia or something that tells you exactly what you have to use for instance if you want to write um a special language in india or pakistan like urdu or whatever you'll have to find the correct language code for that so but you can google that easily so um i'm not gonna present all those languages code language codes in this chapter but i'm just giving you the tools necessary to find out on your own okay and that is it really that's all we have to do for the ios app so we've added the cf bundle localizations in here and we're good to go for the info p list then what we need to do in here is we need to go into our root folder of our application and then we need to add a file as you can see on the bottom of the screen called l10n and as i told you this l10n is a it means a localization that's the 10 thing meaning that there's 10 letters between l and n in localization so let's go ahead in here and i'm just going to right click on this folder in here and actually here and then let's add a new file and call it lpn yamo all right and in here then we have to write some stuff and i'll bring the official documentation because it is very very helpful in this case so let's go and have a look at the documentation what we have to enter in this ltn file let's see if we can find it somewhere and it is an arb file so l10n and it looks like this so this is this is like the contents that we kind of need to place in our l10 file so as you can see it says arb directory and it's called lib el tenen all right and we'll soon have a look at what this actually means excuse me and then we have something called a template arb file and then something called an output localization file okay so um i'm going to explain to you what this what these all actually mean so what what this arb directory means is it is an indication for you you're telling um flutters auto generated localization engine where to find your files where to find your localizations you see when you create localizations for a new language then you have to create a an arb file so and you're basically telling dart in this case or flutter in this case that these arb files i'm going to create are going to reside under this folder so if you look at visual studio code here we have now a folder from all when we created basically our project which was called lib as you can see in here okay so in this lib then we're going to create a folder as it's indicated in here called l10n well you don't actually have to call it altenent and that's why you have this configuration so you could call it something else you could call it localization if you want to or my strings whatever you want to it's just an indication to flutter and the localization engine where you're replacing those files okay so that's that so that's you're telling dart where it f it where to find your localization information then in here the template arv file is a file in that directory that you're basically choosing as the main language of the application so if for instance it can't find a key for swedish in the swedish file arb file it's going to fall back to the english one and this is like setting the ground for or setting the foundation for how you're localizing your application you can think of it as the default language that your application supports in our case that language is going to be english so we're going to leave this file name as it is indicated here the other thing output localization file it is a file for that auto generation to basically create for you so as you'll soon see auto generation is very special i mean it's very magic so um but you have some control over it and this is like one of those things that you can control you can actually control where that auto generated dart code is going to be generated and in like what file name it is a little bit abstract so i'm not going to go too much into it and you'll soon see how we can configure this and what this actually means so what we need to do in this internationalization documentation let's just copy this content and i'm going to then go in this l10 and yaml file that we created and just paste it there okay what we need to do in here we're going to leave the arb directory directory as lib l10 because that kind of makes sense okay uh but in here app instead of app ian i'm just going to say intel yeah it's just for me it makes more sense to use the intl underscore en as the default file so we're going to create intl en and then intl sv for swedish okay and then we're just going to leave this as it is so i'm just going to save this file right there and then what we can do is just to do a hot restart now remember hot restarting is something in internationalization it's very important flutter because hot reload won't trigger auto generation of your internationalization code meaning that if you have some if you've added some new strings for instance to your arb files as we'll talk about it soon those things won't be auto injected and generated into your code until you do a hot restart hot reload won't cut it so you have to either do a hot restart or just completely stop the application and build it from scratch and that's a huge overhead so you may not want to do that but a hot restart is necessary for that okay so let's have a look now at um what arb files are as i mentioned before now arb files are application resource bundles and they're pretty much json files they are key values in there and your keys are basically how a handle for your application to then reach into your localization and grab for instance a string and the values of those keys are the actual strings that will be displayed in your user interface they are more than just key values because you can actually put logic in your arb files in that for instance as you soon see inside this screen let me bring it up in scr cpy and if you log in with a valid user in here and we have foobarbas as our password i think um in this screen at the moment on the top of the screen we're seeing your notes but what we're going to do in this chapter just to demonstrate how arp files work we're gonna say if you have one note it's just gonna write no you have one note something like that or one note if you have more than one note then it's gonna say for instance if you have three notes it's gonna say three notes or if you have zero notes no notes at all it's gonna say you have no notes so for the same title which is the title on top of the screen we can actually put logic into the arb file to say hey this isn't a title however i wanted to say this if this particular count is zero i wanted to say you have no notes if the account is one i want it to say you have one note or if the count is more than one i wanted to say you have x amount of notes and that x is the actual number that we will provide to it so rb files are more than just json they can actually have logic in them and they stand as you can see at the bottom of the screen they stand for application resource bundle all right and now what we need to do is to actually go and create these um files so let's go into this lib folder and let's go and create our the folder that we mentioned in this l10 and you see we said that under lib we're gonna have a folder called l10n and under that l10n we're gonna have a file called intl en arb okay so let's go ahead and see if we can get that to work so in lib let's go and say new file and then i'm going to say l10n slash intl en arb and you can see that it creates the folder as well lib l10n and intl enarb and that is the file that we said we're going to create here let's then go ahead and say new file intl and then we're going to say sv arv okay and as i mentioned before these are very simple jsons to begin with so we can just create a json for instance here and in the english one first so like this and in here i'm just going to say my title and then a value of my title goes here okay and let's just copy and paste this in the swedish one as well just for now okay so and i'm just going to do a hot restart all right so what this all did since we've added our auto generation in our pop speaking ammo if you remember from before we added this generate true inside here now what you should be able to do is to have a look at the structure of your project and now all of a sudden you should be able to see a folder called dot dart tool and if you drill down in there you should be able to see something called a flutter gen and if you drill down in there you'll see gen l10n and in there you'll see now three files app localizations app localization sv and applicalizations en now what is this app localizations well if you remember from our um l10n we actually told the generation to generate generated code to be named app localizations and that's basically it that's that file we said that it needs to be called that so we can open that and you'll see now there's some information in here and there is a locale name for instance and then there are some delegate stuff and i'll explain all these but what you'll see here now is something called my title and is a string and this is exactly what we wrote in this my title my title goes here and you can see then if you go to the english one your string is there my title goes here and the swedish one is also saying my title goes here so it's not so it's not so impressive since we actually chose to have the exact same string in the english and the swedish version so what we could do is to go to the english one in this intel en arb and put eng at the end of it and go to the swedish one and say swe like in sweden okay and then i now get a a save on this file and then if you go in here you'll see nothing has changed and that's what i meant hot reload doesn't cut it you have to do a hot restart and if you do a hot restart then this code should basically get updated let's go ahead and see if it did you can see here's the english one oops i didn't mean to change it and here's the swedish one so now you know what those things actually stand for and we now have a really good ground to stand on because we've created our localization yaml a configuration file we have our english and swedish localization files right here in lib if you have a look here lib ltn and under those we have intel en and intel sv which means intel internationalization english and international nationalization swedish now all we really have to do is to basically go ahead now and start populating these um strings in our application and um kind of sorry populating them in the in these arb files and then where in our application we have text hard-coded then we're going to switch to using these strings which are in our l10n file and in order for our application to actually understand what we have localized in inside our arb files we have to actually tell the application which locales we support and in order to mention sorry in order to explain that we have to go back to the main dart file so let's go to main dart file and have a look at how we've created our application and you can see we have this code right here that at the moment says run app and then we're creating a material application and there are two important properties in the creation of material app which we haven't used so far because in the previous chapters we haven't done any localization of the application so far so these two properties are namely localizations delegate and supported locales so let me bring up the caption for this section um the way flutter localization communicates with the ios app and android app or for instance a web application or desktop whatever you're running flatter on it needs to tell the underlying operating system what locales and it's supporting so basically that's telling your material application which languages your application is built to work with so that's the locale so you could say swedish english persian and arabic or what have you so those are the locales but you also have the concept of localization of your widgets you see at the moment we've created some strings and and also we're then gonna soon go and place those strings on our ui but also flutter itself has localization support for various languages there are so many languages that flutter at the moment supports and it can internally also localize its own widgets for instance if you bring up a date picker for instance in your flutter application for user to select the date that day picker itself can have localization based on the system's language or your application's language so if you've chosen arabic career applications language versus at the os level then and if you bring up a date picker then that date picker is going to be localized for that language by default by the flutter team so you need to tell material app both about the locales that your application supports also how it should localize for instance internal widgets and also your custom widgets so what we need to do is to actually go and add these two properties here and what we want to do is to refer to this app localization file so if you go to dart tools and you can see there's this app localizations right here and you can see there is a pop speaking ammo and and then this is basically a package so it is a package that was created for you you haven't done anything it's just generated for you so how do we go ahead and import this in our application and that is by going to the top of your main file for instance and say import and then you say package and then in here we just say flutter underscore gen and this is like the generated code for you and then gen l10n and in there you'll see that there is applicabilization's dark files so i need you to please go ahead and import this file into your main dart file after having done that we need to go to the material app and right before we do anything else we're first going to say supported locales this is a property and that allows us to tell flutter which lookouts our application supports now you may be wondering okay what data type this is this is actually a list as you can see it's an iterable of locale and some people go and incorrectly create a custom list of accounts and then put that in here but you don't have to do that and i actually suggest that you don't do that even if you can because if you go inside this applicalization start file you see that something down here it is created for you calls supported locales so it is already understanding what locales your application supports based on the arb files that you've provided to um flutter gen so please don't go and create the same list in your main dart file in here what you'll need to do is just to say applicalizations and then you just say supported locales okay so this goes and uses your arb files as like a guide let's see lib ltn and ar b fast it just knows that you're supporting english and swedish at this point okay so that's the first thing that we have to do the other thing that we have to do in here is just to say it's called localizations delegates as you can see it says the delegates for this apps localizations widget and this is basically a way for you to tell flutter that hey i support for instance swedish and english please localize your own widgets as well so in here you don't have to create custom delegates because those are also provided inside your applicalizations so if you go in there you'll see something in here localizations delegates all right so what we need to do now is just to say applicalizations localize app localizations and then localizations delegates so then that is provided and i'm going to do a hot restart just because we've changed the main function in our application and those changes aren't going to take effect until you do a hot restart okay and what we can do now is to go ahead and test these changes and um what would be really great is actually if you could extract that little title that we've written in our intel en arb and and put it somewhere on some sort of widget just to see that it is working in english and in swedish so what i'm going to do is i'm going to bring scr cpy on the screen right here at the moment you can see we're on the login page so let's go to the login page and you don't have to do this so i'm just going to do this myself just to demonstrate something and while we're in the login page let's also clean up these two unused imports okay and let's go ahead into our code here to the login and you can see there's a cons text login but in here we want to use that title and again you don't have to do this and i actually suggest you don't do it it's just for me demonstrating to you that hey it's working as expected okay so just follow along and look at this part without having to do it yourself so what we need to do in here let's go and import the same localization so i'm just going to say import package and then we had flutter lock what was it called let's go to main dart file and and exactly copy and paste that flutter gen okay and i'm gonna bring it into login view dot dart i'm gonna paste it there so we also have access to our localizations and the way to grab your localizations is with this code so if i write this for instance just in here i'm going to remove actually let cons be there i just want you to see why we have to remove const in the future so for us to be able to grab this string which is my title in our login view we have to say app localizations of context and then we can say my title and then we have to explicitly on wrapless okay so this is how you grab a localization out of your um supported localizations basically the stuff that you placed in your arv files okay so now we have my title and in here as you can see it says hey a value of type null can't be assigned so basically this is an issue with having constant here because in in the previous i mean up until this point the way we've created our app bar was that we said that is a constant string it's a constant text that says login but now that all of a sudden we're saying we're retrieving this text from our applicalizations these properties unfortunately are not defined as constants so if you go in here you can see it's just a string getter and that's the reason you can't have cons in here so i'm just going to remove that cons it's going to be very happy and the reason we have this exclamation mark in here is that the app localization is off function and you can see it returns an optional application it is a bit unfortunate i don't really like the syntax that everywhere we have to go on applications of context and a um an exclamation mark in here and we're actually going to fix that soon right after this demonstration and because this is as you'll see soon it is soon gonna get quite annoying to have to always say applicalizations of context exclamation mark dot and then the name of your property but so hang on we'll fix that soon so now we have the login in here and i'm going to do a hot restart and let's see what we get i'm going to bring scrcpy and now you can see i see my title goes here swedish all right and that's the title that we put in the intel um swedish you see right here okay so we have that english one let me bring the swedish one next to the english one as well like that so we have the english one and the swedish one here and you can see at the moment we're seeing the swedish one and the way to actually change the language of your um phone on android is a little bit different from ios so here i'm just going to go to install nina and that's settings and in here i believe it is somewhere it's in system i believe and then spirowak which means language and then i'm going to go to language and at the moment spirowak here is swedish i'm just going to bring english on top and you can see now english is on top so let's go back to our application and see if its title is going to change and now all of a sudden you see that it's displaying the english title so it's working very very well on android i'm gonna get rid of the scr cpy on the screen and bring up a an ios device which i've created with um so it's an iphone 12 pro that is sitting on my desk right here and i have quicktime which is mirroring that iphone screen here so let's go ahead and in here stop the process on android and then command shift b on macintosh to select the device or control should be on windows and linux and say select device and then i'm going to choose that iphone 12 pro and i'm going to go to the main dart file because that's how we should run the application because if you try to run the application when you're on this file it's just going to give you an error telling you hey i don't know how to run an arb file so that's the reason you always have to go to a dart file in your application so that visual studio code at least knows how to run your application so now let's bring up um our um quicktime here and let's wait basically for this running xcode build process to finish and as i've mentioned before sometimes xcode can actually be much slower than building with gradle so that is quite annoying um so i'm just gonna wait here until this process is done let's see how long it takes oh it's installing that so i don't actually have to do anything so installing and launching it says at the moment so let's get ready let's see how long that takes and i can see now that it's going to install the application right here we should see some sort of progress on my notes right there okay now it is launching the application and we can see that at the moment the user and face is english and um so i'm gonna close this widget and then bring visual studio code here as well all right fantastic so um unfortunately mirroring an iphone a real iphone on your computer screen with quicktime isn't going to allow you to interact with that iphone at all and scr cpy is very special in that it connects with adb and at the low level it allows you to interact with the screen however the same thing isn't true when you're mirroring an iphone screen so right now i have to go and interact with this phone by hand so i'm going to grab this phone and it is right here i don't know if the cable is long enough for me to show you so here is the phone right there and i'm going to then go to system settings right here and i'm then going to go to general and um and then let's go to language and region and in there i'm going to choose swedish right here and the the thing that is a bit disappointing in ios is that the language that you choose for your system is for the entire system and when you do that it's going to kill all the running applications because ios applications don't have the possibility to change their language on the fly that's something like android does very very well in that you can change the language of the entire system and nothing has to restart the applications keep running you could even see when we changed the language the um like here we couldn't we didn't basically see the application terminate or anything so what we need to do now is to ensure that we don't change the entire system's language instead i'm going to show you a way that you can choose to do in ios that changes only your applications language so let's go back in here and let's go and find our application which is called my notes i believe somewhere and let's see if you can find it and it's right there my notes and now you can see that there's a menu at the bottom of the screen that says language and then i'm going to tap on that and then i'm going to choose swedish and the reason that you're seeing these two options in here because the change we made in our info p list so if i say main sorry info p list we can see that we said english and swedish in this order and that's why they are displayed here also in that order so i'm going to then choose swedish and as soon as i do this you'll see up here that our application will terminate because ios can't handle that so and there we go the application's completely terminated now but that's okay so i'm gonna go back here and then open the application on ios oh now we have to debug it as well okay because we're in debug mode so let's go ahead and main dark file and then run the application again and you can see it says in ios 14 plus debug mode flatter apps can only be launched from flutter tooling ids with flutter plugins or from xcode so this is a little bit unfortunate as well um because then you have to basically run your build over and over again just while you're testing and this is another i would say it's one of the shortcomings of running applications on ios as well like there are so many things i feel like android is ahead of ios that it's just android is a little bit more developer friendly i would say the tooling the whole operating system is a little bit more friendly so let's see um i can see now at the bottom of the screen it says installing and launching so let's have a look here now our user interface should be in swedish if everything goes well of course and if things are going well then on ios we don't have to do this process over and over again so it's just just to make sure that it's working for the first time as you can see now after changing our applications into language to swedish now we can see the swedish title being displayed on top all right so i'm going to close the widget inspector right there and i'm going to stop this process and i'm going to get rid of this and now we should be focusing only then on deploying on android because it's just so much easier so let's go and do a flaster select and then i'm going to say i'm choosing to run my application on my android device then i'm gonna put away my iphone great so that is that and and the thing that we need to talk about now is at the optionality of this app localizations so if you go back to our login view you saw that applicalizations of context is an optional value because this function returns an optional app localizations and there is a way to make this better it's one of my favorite ways it's like the shortest extension that we can write in our flutter career progress but it's one of the most powerful as you'll soon see in order not to have to repeat this code what we could do is to create an extension on build context that grabs its applicalizations and returns it as a non-optional value so here we have applicalizations being returned by passing the context in but what we are going to do is to grab the applications from the context itself all right so let's have a look at um how we can actually do that in order in order to get started let's leave this code as it is right there we don't have to do anything special but what we're going to do is to go as you can see at the bottom of the screen we have to go and create a new file under lib extensions and then we're going to create a new folder as well called build context lock dot dart and lock as in localization in this file we're going to create our extension on build contacts that allows us to return our localizations to the caller all right so let's go ahead and do that i'm going to go to lib in here and then we have um as the bottom at the bottom of the screen says extensions we already have the extensions folder but we only have list folder in there with a filter file so in extensions i'm just going to right click and say new file then let's go ahead and create build context slash lock dart okay and in here what we're going to do is to say um import our flutter sorry package after gen as we did in the other places and then gen l10n applicalization starts okay so that's the first import and in here we don't we only need a few symbols or actually one symbol which is the applicalizations but we'll talk about that soon so let's go ahead and say extension um and we're gonna say localization on build context as you'll see it says i have to also import this because it is in material so i'm gonna say go ahead and import it and i really don't like as if as you follow along with this course i don't like to import everything in material like if i only need build context i only need build context so i'm not going to import everything so let's just go ahead and say show build context and that only brings build context in this context so what we need to do in here we're going to create basically a getter which returns app localizations applocalizations we're going to say this is a getter and it's called lock and what it does is is returns applicalizations of this and it puts a an exclamation mark at the end of it so and also you'll see that we've imported applications as a whole but we only need app localizations from that file so i'm just gonna say show this okay so that's that file now it's created and and while this all is going on i'm gonna select that and also i'm gonna say run because it is always good to have the application running as we're doing hot restarts and hot reload so we can see the results on the screen so with this extension now you're soon gonna be able to say build context dot and then you can get your localizations so let's go back now to this login view what we wrote here as you can see is this syntax at the moment but what you can replace the syntax with is if we remove this and we just say context which is our build context and then you say dot lock and you'll see here it says oh i don't know what lock is and that's correct it doesn't know what lock is because we haven't imported that extension sorry about that i'll just close the switches inspector so it doesn't know what that is so i'm just going to say command dot and it's going to auto import it for me great and now we can just say my title i mean tell me this isn't better this is for me 100 times better like if you compare this with what we had before which was this i mean come on it's a lot shorter a lot more is the same and i personally think it is it is a better code so let me go back all right so let's leave this here for now okay just my title let's leave it there and let's go to our android application which is scrcpy in here and we can see that it's displaying the correct title so if i do a hot restart as well it's still going to work and display the string from our um from our arb file now that we've done this we actually have to talk about all right how are we going to go about localizing things well this is the important part you see localizing is in a lot of places quite a boring work in that you have to literally go for instance if if you're i mean it is boring if you're doing it the way we are doing it in this chapter and that you have to go and collect all these strings excuse me and then you have to go and place them in your arb files and then you have to also place them in the swedish arab file and then you have to do the translation etc so you have to create keys for all of these so this is quite a boring work and it is not something that we're gonna do in this chapter because i've already prepared all those for you so you don't have to go and write them by your by yourself so what i'm going to do here is i'm going to literally go and bring all those strings that i've prepared for you and let me see if i can find them somewhere in the en rb okay i found them right here and what i'm going to do then is i'm going to just bring all those strings and place them in our intel en arabi file so here you see at the moment we have my title and i'm just going to leave my title in there because we're using it right now but we're going to have to delete it soon and i'm going to paste all these strings that i've prepared for us okay so there we go all of those are here now and there is a github repository for this uh for this uh course of course and you can go after this chapter is done you can go to that github repository and retrieve all these strings so you don't have to type them by hand either so it is nothing n nothing at all special going on about this as you can see we have just a logout button that says log out we have versus a cancel button we have the verify email which is something that we're using in the verify email screen for instance we have the register button we have the restart button let's see where the restart is used it is i believe oh restart i believe it is inside the verify email screen so if i created for instance um if i say pixel to a b gmail foo bar about and i say um oh sorry to register screen so let's say pixelity gmail.com foo barbaz i'm gonna register this user and then we're gonna go into this screen at the moment it says restart and that's this key restart okay so i literally gone to through all our screens all our dialogues as well and collected all those strings and placed them here in this international internationalization enarb file and i've also done the same thing for swedish so i'm going to go and bring those files i'm sorry bring those keys in here so i've done the translation to swedish and i'm not my mother tongue isn't swedish so but i've lived in sweden for a long time so um i can't speak swedish a little bit actually enough i can speak enough and i'm gonna paste those string in strings in here as you can see they're completely in swedish okay so what i've done is literally we have the english ones you can see here and we have the swedish ones so it's the same keys but different values and again don't worry i understand if you're watching this course you're like oh but how am i going to get all these just please go to the github repository and you can extract these values you don't have to type them by hand and you should be good to go so now we have these in order for our localizations to be generated in these dark tool files let's go to flutter jan and have a look at this gen 10 l gen l10n you can see those strings aren't here at the moment because only my title should be here somewhere let's see if you can find it let's see en locale should reload my title you see nothing else is in here but if we do a hot restart all those strings should get generated and then we should have them all here you can see login verify email all these are provided right here okay so that's that part so now we have all our strings and we should just be able to do the coding part which is the fun part so let's go ahead and take care of that i'm going to close all these files that are there at the moment so we have a clean slate to work with the first thing that we're going to do is to localize our um what is it called cannot share empty note dialogue so let's go ahead in there and then i'm going to say command shift p and go to cannot share empty now dialog if you remember if you're if the user is trying to share a dial sharing note that is its contents is empty so sharing in this case we have a key for it so we're just going to say context.lock and remember this lock is an extension that we've created we don't have access to it unless we import it so i'm just going to say command dot in visual studio code and it's going to also import that file for me just right here as you can see and now we have access to all our strings okay so in here we're just going to say sharing which is a key i've created remember all these keys are in the arb file and you cannot share an empty note so we're going to say context.log cannot share empty node prompt which is a key again i've called an okay we also have okay right okay so and now we've localized our show cannot share empty notes dialog fantastic so let's go ahead and localize our delete dialogue so i'm going to say command shift p visual studio code on mac or control should be usually code for windows and linux and this and let's say delete dialog in here we have this um little uh title in here so let's just say um context dot lock and remember we're in a new file we don't have access to log let's auto import it and in here i'm just gonna say delete that and prompt we're going to say context unlock and delete nodes prompt cancel context dot log cancel and here context.lock and was it okay or it's yes so let's just say yes all right so that's the localization of this file as well i'm going to say command command s or just hot restart the whole thing maybe it's better and i can see a crcy crashed unfortunately and that's the problem i've had with this cr cpy for a long time that's okay it's an open source software i'm just gonna say select device and this and i'm gonna run the application so we have it running in the background fantastic so uh that's the delete dialog now i have to capture at the bottom of the screen in case we have to go and localize pretty much everything in our application up to this point and now the next step is to localize the error dialog so let's say error dialog and in here let's just you can see it says an error occurred and we've called a generic error prompt in our arb file if you look here generic error progresses and error occurred okay so let's go ahead and use that here so i'm just going to say context.lock auto import i don't have to explain that anymore and then we say generic error prompt we have an ok as well so context lock okay so that's done as well then we have to go and localize our log out dialog so let's go to log out dialog and here log out dialog and we're going to do the same thing in here so let's just go ahead and say that we're going to use the log out button in here and you see we have log out in a few places like if you remember in the main application interface when you're logged in with an actual user i'm going to bring in crcpy so you know what i'm talking about if you look at this screen if i say restart and if i log in with a user and i say van.mp gmail.com fubar as when you log in with an actual user then you have this little log out in here and it says log out and at the same time when you tap on it then there's this dialog that says logout so we have a choice in here either you go and define two log out strings with different keys in your arb file or you just define one and that's exactly what i've done so we're in here i'm just going to say context.lock that's how to import and in here we're just going to say log out button okay and it says log out button i understand it's the title of a dialogue and we're calling the log out button you may just go ahead and call this key log out if you want to i'll just call the log that logout button remember these are just keys you can change them easily okay now that's that's for our title and then for the content we're going to say context log log out and dialog prompt and we have a cancel button here so let's say let's just say context log cancel and again we have another log out button you can see here so log out here log out here and then log out in here so there are three places using the same thing or same string context log and then we're going to say log out button all right so that's great so that's that part as well i'm just gonna do command s to hot reload the next thing that we have to do at the bottom of the screen in the case in the caption we have to go and localize our password reset dialogue so i'm going to remove log out dialog here and close the tab and let's go to password reset email sends dialog and in here we have this password reset and i'm going to go to my notes as well so let's go in here for the title and say context block auto import and we're going to call it password reset it's one of the keys i define and in here we're going to say context lock password reset dialog prompt okay and we have an ok button so you now by this point that we have an ok key as well in our in our arb file so now we've done basically we're done uh localizing the show password recent dialogue uh uh show password reset sends dialogue okay the next uh dialog is um forgot password so let's go to that screen that sorry this is not a dialogue this is actually a view so we're going to go to forgot password view here i mean when it comes to views our job is a little bit more difficult because up until this point we've pretty much everywhere used constants like if you look at this is a constant string here's a constant text here is constant so everywhere that we're going to localize our strings and we were using const before we have to remove that cons now because our localized properties inside arv funds are unfortunately not defined as const and i don't really know the reasoning behind that simply maybe because there are getters and maybe getters can't be constant or there are some other problems with the generation maybe that um the flutter team decided that well these can't be constants but that's something that's the truth that we have to live with at the moment so let's go ahead and find all our strings and we're going to start localizing them one at a time before i got password view so here in this show error dialog and i've called this key forgot password view generic error so let's remove this string and just say context lock let's auto import log and we say forgot password view generic error and i'm going to put a comma at the end so it's formatted nicely so let's go to this forgot password title itself so i'm gonna remove the const remember i just explained that so we're gonna say context log and we're gonna say forgot password that's the key i've defined and you can also see its description here and you can see it says forgot password okay in english this message translates to forgot password okay so this thing i've called it forgot password view prompt so let's remove the const remove the string itself and we're going to say context log forgot password prompt forgot password view prompt and put a comma at the end and let's have a look at the documentation for this as you can see it says if you forgot your password simply enter your email and we'll send you a password recent link okay so that's one thing and then in your email address um it says input decoration your email address because that's a forgot password screen let's go here and have a look at it see how it looks like here i forgot my password so here's that little input decoration so i can see i've called it email text field placeholder so let's remove this const and in here we're going to say context log email placeholder text field okay let's go ahead and have a look at this one so let's remove the const it says send me password recent link and i can see that i've called that forgot password view send me link so context log for god password forgot send me link here and put a comma at the end so the dart formatter gets busy with formatting the code and in here back to login view i can see that i've called it forgot password view back to login so context here context lock forgot back okay so and this is this is a technique that you can also use like if you want to get like a property like this that's quite long name and you want to get the name immediately right you could just write a few keywords of that name for instance i know that for god and back are quite unique names so if i say forgot back it it's gonna show me that so it has this like partial search kind of in its intelligence which is very very useful the next thing that we have to do is to go ahead and localize our login view so i'm going to close the screen forgot password view and go to login view login view right here and we're going to start at the bottom at the top of the screen and we'll remove this unused import right there in login view and let's go ahead and start by uh localizing our dialogs so the first one is cannot find a user with the entered credentials and i've called it cannot find user or login view cannot find user so i'm just going to say context.log let's auto import log or it was already imported okay that's great and let's just say it is called login error cannot find user cannot find user okay the next one i'm going to put some commas in here get dark formatter to do its job correctly and i'm going to press command s to save the file and that's going to format the file for me for wrong credentials i've called it login error wrong credentials so context log and wrong credentials next one is authentication error and we just call it login error author so context lock author okay so that's that one as well now at the top of the login login view we have this little text that says please log in your account in order to interact with and create notes and this one i can see i've just called a login view prompt but i wonder what happened to our title as you can see we have this my title now that we're in the login view it is a good time to actually go and get rid of that okay so i'm going to open um intel e and arb and i'm going to kill this basically my title and i suggest that you also go to the swedish file which is intel sv and kill this title as well okay so we've removed that and i'm gonna get rid of that then i'm gonna hot restart so that the code generation kicks in and as you can see in here my title isn't valid anymore and in this i mean this title is called now login if you can look at the documentation in here you can see in english it just says login fantastic so let's remove this constant here from the prompt as well and we're just going to say context lock and let's just say login prompt so i'm going to do a prompt okay so for the enter email um text field placeholder here enter your email here we're gonna remove the const and let's just say context lock and we're gonna say email placeholder okay and we also have an enter your password here placeholder so let's remove the cons in here i'm just gonna say context lock password placeholder okay password field password text field placeholder that's the full name and we have this uh login in here so what we need to do is just to change this text as well so let's remove the content here i'm just gonna say context dot walk login and i forgot my password so i'm going to say context lock and i believe it's called forgot password login view forgot password okay it's not a constant anymore and put a comma here it's just good practice to put comma at the end of your parameters even if it's just one argument that you're passing to a function i mean my reason this is a little bit of a side though but my reasoning is that any time in the future anybody anybody wants to add new parameters to this text widget then they will have to go and put that comma in there but if you as a programmer who wrote this code in the beginning you put the comma in there you're kind of like acknowledging the fact that hey i appreciate your time you may be wanting to add now you may be wanting to add new parameters to this and i've already prepared this for you so if you don't do this if i want to as a programmer add new parameters in here i have to go and say oh well okay comma commandments go here blah blah but if you'd added that already i'll just say enter and then write my parameters okay great so what we can do now is to scroll forward here and localize the rest of these properties and it can't i can just see here that we have one property left here which at the moment says not registered yet registered here so let's go ahead and remove the const as we usually do then and say contacts lock and i can see it's called not registered so let's use that and a comma here so we prepared for the next programmer so to say and we could just say now that we have successfully localized our login view at the moment so we could just close this tab the next step is to localize our register view so the register view also has quite a few things that we have to localize so let's go ahead and go to register view and while we're here i mean this is what i'm again i when i started this course i wanted you to become a software engineer even if you were like a designer a ux or whatever or project manager and you have to put yourself and your yourself in the shoes of a software developer software developer you're always in like time constraint usually our time concern to deliver but at the same time when you stumble upon something that is quickly fixed please do it on right there uh at that point because if you leave these things they're gonna pile up and many small things that could be corrected on the fly if you just leave them they're gonna become a big pile and then you're not gonna be able to have enough time to fix them all so while we're here we have two unused imports let's just remove them because that's just good practice not to have unused imports now let's go to our register view here we can see there's quite a lot of errors there are four errors so the first thing i'm gonna do is to put commas at the end of these right there and i'm going to press command s on macintosh or control s on windows linux and that's going to do the formatting the first one is called weak password so let's just say context lock and also import this and this message is register error weak password so weak password like that the next one is called context log and it's called an email already in use okay fail to register i've called register error generic so context lock generic here it's register error generic and this invalid email is called context lock and register invalid email okay so those are our errors we didn't have to change anything with constant because these messages weren't constant when they were passed into this constructor then we have to fix this register's title and it's just called a register so i'm going to remove the con const i'm going to say context log register here and then we have enter your email and password to see your notes and i've called that the register view prompt so context lock register view prompt we have this input declaration again we've done this before with the email and password so it's nothing surprising so let's just say context block email placeholder and this one is a password placeholder so let's remove the const a context lock password placeholder all right so that's that then we have the register button that we also have to localize and let's remove the constant here and just say context lock register and already registered is called already registered so let's remove the constant const as well and we say context lock already registered all right and a comma at the end as well and we could do the same thing in here with a comma at the end just to do the formatting right okay so this seems to be ready we've now localized the register view and the next step is to localize the verify email view so i'm going to close this file and let's go ahead to verify email view and again we have two unused imports let's remove those and let's go ahead to verify email in here and we've just called it verify email so i'm removing removing const saying context of lock and let's say verify email okay and this is one thing that i've also fixed and you could see that in how we've developed the application so far we have two texts on top of the verify email view and they kind of look like this if i bring it up let's go to try to log in with a user who hasn't verified his email and you can see we end up here we've sent you an email verification please open it to verify your account and this is like there are two text fields but what i've done is i've made it one text prompt so let's just remove the second text field and the way i've created this it's um if we go to our intel en rb and if you look at the verify prompt you can see i've written we've sent you an email verification please open on your open it to verify your account and then the rest of the string it just follows along so it's just one paragraph and so that's why we're removing the second text in here so and we're gonna remove this const i'm gonna remove the text and then we're going to say context lock verify prompt okay and a comma we have this a little text button in here that says send email verification and this looks like this let's change that as well and here we're gonna say context lock and it is called verify send email verification put a comma here okay and for the restart button we have a restart text so we're just going to say context log restart and a comma at the end all right so that's the localization of this screen as well so we could say we're pretty much done with the verify email localization as well and while we're here to be honest with you we could also clean up a little bit here in this verify email while we're basically cleaning up the view itself you can see that this text doesn't have any padding what we could do is to in this whole column actually maybe pad this text so we're going to say this text is padded wrap it with a padding okay and we could just say padding of 16. so you can see now it is a little bit cleaner it's just a very little uh effort to make the the ui look a lot cleaner okay so we're done with that screen and what we need to do um we need to actually localize the create update node view so let's go ahead to create update note view another unused import let's remove that and let's have a look at what exactly we have to localize in here it's probably the the views title so if we scroll down to where we're displaying the new note so if i log in with the user who has verified his email address this user our baz horrible password please don't use that password at the moment you can see in here we're basically saying um sorry new note here we're saying new note and that's this thing so let's just change that and say context dot lock auto import disk oops how to import this and then we're just going to say note okay and you can see in the documentation it says it just in the english one says note so here we're not saying new notes and the reason behind that is that up until this point our application is being say new notes but what happens if you tap on an existing note it still says new note so that's the reason i've decided to basically change this text just to say note and put a comma in here to prepare for the next person as well and what we're going to do and is also to change this text decoration and which is here it says start typing your note okay so remove the const and then in here we call it start typing your note so context log start typing your note all right great so we're going to save that as well and we're done with that so now we're going to go to localizing our notes view and this is i would say this is like the most exciting localization part because we need to do some more coding it's not as easy so for just two just to because remember in the beginning of this chapter i mentioned that arb files are more than just normal json in that they can have logic in them and at the moment if we go back to our let's see if i bring scr cpy here at the moment you can see it just says your notes and i wanted to kind of demonstrate how arb files can be quite dynamic and can have logic in them and i thought okay how do i demonstrate that to you and what i decided to do is um that if you land in this page and you have no notes like in this case at the moment it says your notes but what we're gonna do is to say okay we have some some key in our localization file that is called your notes okay or sorry it's called notes title is a key but this key is going to have some value that has actual logic in it and this logic has to do with the plural pluralization of this key if you have no notes in english we're going to say no notes yet if you have one note it's just gonna say one note and if you have other number of notes such as two three four then it's going to say x notes for instance x being three notes four notes so it's just gonna say four notes so no notes yet one note or x notes so it has pluralization built into it and how we have to do that is to use something in arb called placeholders and i'll show you how to do that right now so let's go ahead first into our intel en and at the bottom of the screen here what we're going to do is to first create our key so that's the most important one okay so we're going to call it notes title and in here we know that we're going to have some value and let's see we have also a semi sorry a colon there okay so we have notes title how do we put our logic in here we just know that we need to have some sort of a account you see your localization arb file doesn't know anything about the count because it's the application that knows how many nodes are available in the in the fire store database so somehow we need to pass this count to our application sorry to our arb file and you do that with parameterization so you go ahead and create curly brackets in here and you would say okay hey i want to have a parameter called count this count needs to be passed to this um notes title in order for it to be able to calculate exactly what it has to return so it's just you saying that hey application if you want to get the notes title localized string you have to pass a parameter to me call count okay now what we're going to do is to go and call and basically and create discount as a parameter so what you have to do is to go to the next line and just say adds notes title this is how you tell arb that hey this notes title key has some extra logic in it okay then there is a key in here called placeholders so you have to write placeholders okay and in here basically you say placeholders and then every key is the name of the parameter itself so account all right and then you basically start that and then what you have to do is you have to define two keys in here one is a type and the oops type and then the other one is an example like this so let's have a look at how this actually looks like so basically what we're telling and arb is that or dart in this case we're saying that hey this notes title key in our arab has a parameter called count and in in here we're saying hey these are the placeholders the name it's count and it's type now you have to define a type you have to actually tell dart that hey what data type is this using is it a string is it's an integer is it a boolean what is it so in here you just say it's an integer and then as you'll see soon the code generation then has a look at this and says okay i expect you to send an integer and it's going to create a function called node's title with account a parameter of type integer so this is very important it's the data type of that count parameter okay and an example is just for you to know okay how is this going to be used so an example is for instance three nodes okay so we're just going to say here's an example of how the result of this thing can look like right so what we need to do now is to tell this um erb and dart code generator here that this count actually has a logic about it being plural so it has pluralization logic and the way to do that is you put a comma here and you say plural and a comma after that because then you have to specify the logic for that pluralization so and look as a side note i completely understand that this is so weird i mean it is a strange syntax i don't feel comfortable with it i sometimes use i sometimes look at the documentation just to be a reminder of this logic but the way i look at it is that it's the best thing we have let's not hate on it let's just use it let's understand that it has power there are reasons for it being the way it is and even though we are not 100 like in in we weren't involved in the reasoning of this we don't even know what the reasoning is but this is what the format is and this is what we have to basically go with so the way to create this is for you to uh have your logic in here so we're going to say equal to zero and let's just do it like this and then we're gonna say equal to one and then we're gonna say other okay so this is how you create it so you're saying that if the value of this count is zero then we are going to do something here if the value of that count is one we're gonna do something here and if it's anything else denoted by other we're gonna do something in here so let's say when it's equal to zero we're gonna say no notes yet okay so that's the string we're gonna display if the count is zero if it's equal to one we're just going to say one note and then the important thing is if we end up in this situation if it's other then we want to say in this case we actually want to get the count so if you pass the value of three we want to say three notes so the way to get that count is with another curly bracket pair and you say count and then you say notes okay so that's how you create these things so um and i think we're actually missing a curly bracket and that is the the curly bracket at the end yes this curly bracket which belongs to like if we if you look here if i remove these the other has two curly brackets and it's two curly brackets and here other one curly bracket there one curly bracket here one ends here and one ends here so this last curly bracket here is for the curly bracket that started here so again i i don't know what to say this is the format the way it is we just have to live with it okay so we've created the notes title and what we're going to do is to go ahead and do the same thing but for swedish and i've already prepared that so i'm just going to go ahead and grab that string from the swedish one that i've already made so we don't have to type all that again so let me go and grab that and bring it into l10n sv which is for swedish and then bring it at the bottom of the screen and paste it right there and with a comma at the end of that line so you can see plural and it says no notes yet for one it says one note and for other it just says x notes all right so i'm gonna save this i'm gonna save this and i'm gonna do a hot restart let's just hope that scr cpy doesn't crash and it didn't so what we're gonna do now is i was as it was planned we're gonna go to our notes view and i'm gonna go to my notes as well here let's go to notes view and have a look at our title in here and you see we at the moment we're seeing your notes but what we really want is to be able to display the number of notes that are inside our um inside the nodes provider so if we have a look at how we're reading the num and the notes you can see we're using the note service and then we're saying all nodes and this is a stream of an i triple of cloud nodes so we kind of wanted stream builder we want a stream builder to create our title our app bar and we're going to exactly do the same thing so we're going to have a stream builder that creates our app bar okay but or actually it's going to create the text but how do we get the count of the notes and the way to do that is with a little handy extension that i'm going to show you how to create so let's go in here in our notes view and we're going to say extension and we're going to say count and we want to create it on a stream so we're going to say any stream has to be able to like any stream that has an iterable in it that its values are iterable we want to create a property called length for instance that it gets the length so let's go in here and say okay this stream has some value but we want that value to be iterable okay so here we're basically saying that we're extending any stream that contains uh i troubles as its value is gonna have this extension then we're gonna say okay the value of this is gonna be an hint and we're going to call it get links okay and what this is basically going to do is to say it maps the stream's values so let's say event and in here we just say it returns the event's length so i understand this may be a little bit cryptic for you to understand but um you have to know that every stream is a generic function like if you sorry it's a generic class you can see it's abstract class it's it has a parameter called t which is it's generic type so what we're saying here we're saying that okay we're creating an extension on any stream whose parameters or whose types are and i treble and iterable has a length and that means that we can then extend and extend any stream that has an i treble and then we return its property called get length okay so what we need to do now is to go ahead and inside the app bar in here we have a const text when we need to remove this const first actually let's keep it and i'm gonna see if we can wrap this with a stream builder now okay so in here what we're gonna do is we're saying here's a stream builder and we don't yet know what it is it's stream is note service like this and we have all notes and the owner user id is our user id okay as exactly as we have it here okay but here the stream we don't actually want the notes we want the length of notes so let's just say get length where is it here get length okay and now we know that snapshot can then return that uh value for us so if i press command s in here let's put a comma here as well you can see nothing has changed it just says your notes because we're still seeing your notes in here okay but what we want is to grab the data out of our snapshot and this snapshot is an async snapshot of an integer let's see undefined class it's called async snapshots yeah just like that all right so you either could tell a stream builder of int and then your snapshot i believe automatically will be as facing snatch out of it or you could just say stream builder normal stream builder and an async snapshot of it so you could type it in two different ways and i've just chosen to do it this way all right what we need to do in here is to see as soon as snapshot has data then we grab that data which means it has the length built into it okay so we're going to say if snapshot has data which means it has length otherwise we're just going to return const of text nothing meaning that well well we don't have anything to display at the top of the screen if this snapshot has no text all right and then in here we're going to say it's going to say final note count is snapchat date okay or zero because it just says yeah i may not have data just strange because you're actually saying has data but these two properties are kind of like they're different from you i mean they're not different but they're separated from each other just because you're checking something has data doesn't mean necessarily that the next line should understand that it has data the data type of this data property is still final t so you can't change that okay and that's why we have this um elvis sign kind of here or a question mark question mark just to say if this doesn't have any value just use zero okay now that we have node count we have to get that context block and we oh we don't have log let's import that and remember the key that we used intel me and it's called notes title let's say notes title and now all of a sudden you can see it is a function that takes in an integer hello that's the count integer that we built into our arb and it returns a string you can see here that's perfect because then we can pass the note count in here okay and this will be our text and then we could just say return a text widget with that text in it just like this all right and then we can save this and as you can see now as soon as i hit command s it says no notes yet if i say and if i press the plus button here you can see i can type something in here and i go back it says onenote if i create another one on top of the screen it says two notes and that's it pretty much that's the logic that we built into it so now it says onenote delete that note and it says no notes yet perfect so that logic seems to be working fine for us so that's that part and we also have another string at the bottom of this screen which says log out and we have to change this as well so we have to say context log out button and this error is because we it says invalid constant but you're like oh but this is not a constant well the problem is a little bit higher up in that when we created this array of pop-up menu items we said that is a constant so let's remove that okay so that's fantastic and that is i mean now we're pretty much done in the entire application we don't have anything any string that is hard coded and if you look at our problems section there are no problems to fix for instance no unused imports so we've taken care of those as well and just to test this what we could do is just to go to the settings screen here and i'm going to bring swedish up and let's go back to our application here and have a look and it says no notes yet i'm going to press the plus button and i'm going to write some string go back here it says one note create a new one and it says two notes delete this one and all the you see all the dialogues are now in swedish yes delete this note yes let's try to log out now and it says log look at it and it says look go to add a second by the way look at it are you sure you want to log out yes log out and you can see all our strings here basically are also um everything in this screen is also localized so that's fantastic we basically did what we were supposed to do and what we promised to do and that is great congratulations if you then and do what we usually do at the end of every chapter we commit our work so i'm gonna have a look at this and let's have a look at our good status and have a look at our git log as well i'm gonna change the screen layout a little bit sorry about that so you see the code better remove scr cpy make this full screen okay i'm gonna make this a lot larger so you see better and have a look at git log again and you can see the last one we did git step sorry step 31 so let's just say git add all hit commits that 32 okay and get status great and then we're also going to get push our changes and let's tag it as well get tagged step 32 and if you look at our tag all our tags we can see 20 blah blah let's see if we have 31 30 31 and 32 great and then we have to push our tags as well fantastic so um what we've done so far is i mean we've done a lot of work and in this chapter even more we've localized our application we looked at how localization works how code generation for localization works and also we had a look at some important extensions that you can create in order to make your localizations even work better for flutter and we also had a look at adding some logic to our arb file with pluralization so congratulations for going through this chapter i believe personally that is very important to localize your applications you're going to reach a lot more users if you localize your applications correctly for your for like your target markets and um it should help your users also feel more connected to your application so um with that said i may actually then see you in the next chapter hello everyone i can't say welcome to this chapter now because this is not really a chapter on its own rather it is the outro to this course and i don't know it's a kind of a bittersweet moment because uh i've had so much fun putting this course together for you and now i have to say goodbye and um i don't want to get emotional but it is kind of sad uh as it is a great moment of appreciation for you having gone through this course and also i want to really extend like and congratulate you for having gone through this course and having learned as as you've learned because it's it's not an easy thing to do to go through such a lengthy course but as i mentioned in the beginning of this um course if you remember in the introduction i mentioned that um a lot of videos basically jump over quite a lot of information and i didn't want to do that in this course and that's why this course has become as lengthy and long as it has so we've gone through a lot we've talked not only about flutter development but we've also got our hands dirty with some native ios and not really development but all actually going to xcode and fiddling around with some properties in info plus an excel project we've also had to open android studio to create our virtual devices we've worked with figma and design tool we work with app store connect and google play store console so we've gone through a lot so and i want to congratulate you for sticking throughout all this with me and um hopefully you've also learned a lot now while designing this course i also knew that it has to be a living material it can't just be something that i drop out on the internet so i'm very much planning to keep everything up to date but there's lots and lots that i've already planned more to be added to this course so i can't really go into details about what they are i haven't finalized them but just as i did with this course i need to plan them correctly write all my scripts to know what i'm going to talk about and plan even the code that i need to write to tell you all about so just know that there's a lot more to come and you can just subscribe to my youtube channel if you want to keep up to date talking about up to date um things are moving all the time we've been working with firebase for instance and firebase in itself is a moving product so it's an update like ever it's just always updating so new versions come out new versions of flutter might come up come out and new versions of dart might come out so even figma for instance that we've been using a lot the interface might change erratically so since i put so much effort into creating this course i don't want it to die and i'm not going to let it die so it's always going to be updating every now and then i will be putting and not only updated content out like maybe i need to replace some old content with some new but i'm also planning on adding more to it so let's just say that this course is gonna hopefully always be up to date as i mentioned in the introduction of this course i have zero dollars in a budget for marketing this course and marketing is probably the wrong word because i don't actually earn any money by having this course the only thing i earn is joy of having um like people like you going through this course and telling me on social media perhaps about oh hey i did this course and i learned this and this and this and i've released my first application so since i have um no budget for that i would really appreciate it if you could spread the word about it and tell like if someone asked okay i need a course for learning flutter uh it would be lovely and i would really appreciate it if you could just tell them about this course and um i've mentioned this also in the introduction but i would really appreciate it if you could follow me on social media twitter at van.np and also on linkedin because i produce quite a lot of content and as infographics for instance also adds videos related to flutter javascript python django react native swift you name it so even typescript now these days so uh i would really appreciate it if you could follow me on social media and uh i've been told in some places that um by some some of you that maybe some people can actually support me and if you want to do that this is the way to do it just going to buy me a coffee.com but remember it is completely optional it's only if you can afford it so with all that said i don't want to drag on this outro i just want to say again a huge congratulations to you for going through this course with me and spending your life during these so many hours together with me and i've had a blast recording all these videos and uh i'm sure this is not a good buy but rather an official end basically to this course and keep an eye out for more content and i'm sure we'll talk to each other on social media
Info
Channel: freeCodeCamp.org
Views: 2,689,226
Rating: undefined out of 5
Keywords:
Id: VPvVD8t02U8
Channel Id: undefined
Length: 2199min 22sec (131962 seconds)
Published: Thu Feb 24 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.