Complete CRUD App (with SQLite) in Flutter - 4K - 2021

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone it's been a while since i've recorded any videos on uh flutter so i thought to put out a video that i feel very strongly about and that is um crot storage in mobile applications um as you may know crot stands for create read update and delete and these are some of the primary things you may want to do with data insert your app inside your applications or even when you're working with back end you're gonna have um like if you're creating a django rest framework application to return some json data to your consumers whether they're flutter applications native ios or android or if they're react native applications then you're probably going to work with crud as well in that on the back end you're going to create some objects or you're going to read delete or update or maybe all of these in the same application usually so um i thought that in this video we start looking at how we implement crud in flutter without any back-end at the moment and we look at how we can use sql lite to store our data and manipulate the data in a sqlite database now you have to excuse me because i have a new mac here and i've pretty much just set up things yesterday so i don't i may not have all the software necessary to get everything going but um let's just give it a go if i make any mistakes you're gonna see that any developer makes mistakes so i hope that that is okay with everyone so um the goal of this application that we're going to create is to do something as i will show you now i'll make this a little bit bigger so you can see so this is a typical crowd application as you can see here that there are items in a database that we're reading and displaying inside a list the items are displayed as tiles and they each have a delete button and then the ability for you to tap on any item to update its properties now the reading of these items and displaying and displaying them on the screen is the r part of crud and that is read and if you write anything here for instance if you say baz baz last name and then you say add to list then um that is the c part of crud that is the creation of your quad operations and if if you tap on this close button and you say delete that is uh the last bit of crowd which is deletion and if you for instance want to change foo bar to foo baz and save you can see that the list got updated without any flickering or anything and that is the you part of crutch so we're going to take care of all of these in this um video example we're going to have a look at how we use streams stream controllers sqlite databases lists custom widgets so there's a lot of good things happening in this application i think is a good base for anyone trying to get into flutter development just to look at how we are going to develop this application so i have some notes prepared which is basically the uh how i think this application should be developed so from time to time i'll have to look at my notes because there's a lot a lot of moving parts in this application so you'll have to excuse me if i have to look at some notes before i progress to the next step and the ui of the application may not end up being exactly like this we may have to adjust some things or if we find a better solution to how it should look like we will do it as we go along but it's gonna be about this that you're seeing on the screen so let's just get started then um i'm gonna bring up a terminal and i'm gonna go to um projects and flutter and let's create a new project let's say quad example okay okay let's go to flutter let's go to our crud example and i'm going to say code this is this is a an m1 machine so it's not an intel processor and i've had some problems with cocoa pods so recently i had to use bundler to get the pods basically working and i'm not sure if it's going to work on this in this example but we could just give it a try and see i can close this terminal because there's an integrated terminal inside visual studio code which you can bring up with control or control backtick on windows or command back take on actually it's control backtick i think in mac as well and it may be the same shortcut but you can otherwise go to terminal and just say new terminal and it will create a terminal free but now now i have duplicates and i can remove this one which i don't need so now what i like to do is to command shift p and then flutter select device and i'm just gonna say iphone 13 which is my simulator in this case let me bring the simulator up here so you can see it also next to our project and i'm going to increase the size of my editor a little bit so that you can see the code a bit easier i hope so and i'm going to say command p and then say main.dart so this is the code that visual studio or how do i say the flutter command line tools create for you so what i what i like to usually do is to bring all of this uh material app inside the run app so i like to do like this and the same here is a material app and actually we can bring it as it is let's if we remove the comments from here and i'm going to remove the sidebar from here let's grab the material app from here and then we can pretty much delete all of these so delete all of that and just say material app and since we don't have yet a uh my home page let's go and delete this as well then on top here i'm going to say stl which is a stateless and because our home page is going to be a state stateless widget and you may be wondering how we're going to achieve that since in this example you saw that there's lots of moving parts and data being changed but the truth of the matter is that this data is going to be controlled by a class which in itself is immutable so this widget in itself doesn't really have to be a stateful widget so let's write stl and visual studio code and i think um android studio may also support this to be honest with you i'm not sure about it but in visual studio codes please at least you say state stl for stateless widget and i'm just gonna say home page let's go in here and just say home page okay so i prefer const over we didn't run right constantly where the with cons constructor okay we just say concierge um all right let's just see if we can run this as it is or if i have to go and change something in the pods we will find out soon um now it's just a waiting game to get the first build running and as soon as we get the first build running that's the one that takes the most time so um after that is gonna be hopefully a lot easier and faster and i can see that the build actually went fine so we could connect to the application and it's just a black container at the moment and that's because we've just written container here and that's fine so let's get some life into this um application i'm just going to bring my notes up here as well i'm sorry about that so okay let's now say oh i don't want to profile this so uh not sure how to stop the profiling i clicked on it by mistake so uh in here i'm just for now i'm gonna create a scaffold and for the app bar i'm gonna say app bar and for the title i'm gonna say it's a text crowd example okay and here oh this seems to be a new thing that i have to prefer i have to write const like this unlike this all right so we got a simple app bar up there and um there is nothing happening in the application right now so that's kind of expected now what we want to do is if you if you look at the example that we had here every person that is um i mean these are personal objects and every person has three properties the first one is an id which is going to be the primary key of that person in the database and then there's a first name and a last name um and a person for us to be able to for instance create ability to delete a person from the list we need to make sure that they're comparable to each other and also if you add a new item in here you say for instance a test i can't type test name and then we say test last name i can see i misspelled name here again and i say add to list you can see that every item appears on top so these um not only are they comparable and not only they're equitable in that they can be deleted from a list using an equation sign that we're gonna implement later but they're also comparable in that we can sort them using a special algorithm which is it's only being sorted by their ids at the moment so the newest item appears on the top of the list so keep that in mind so we have a personal class that we're gonna develop with three properties we can actually get started with that immediately so let's just say class person um oh sorry about that i am i'm a bit slow today um what properties did we say final um int id then we say final string first name and then we have a final string last name and what i really like to do here is um also by the way before i say what i'd like to do here is um a lot of people ask me what this is why i can see the errors here online and that's because i have an extension called aero lens and you can actually get it from the marketplace it's called error lens it's right here actually um here and this allows you to see all your errors in line so you don't have to like tap on an error sign or anything to see theirs it's good and bad because it i mean it's good because i can see all the errors immediately here but also if you're working with a widget that your return for instance if you're working with a function that has a return value and you're writing a lot of code in there and you haven't even calculated the return value so you don't know what you're going to be returning then the whole function could be highlighted as having an error because it's not returning anything and this error could actually get in the way of you focusing on your code so i would suggest using aero lens until you get pissed off with it or angry at why it's all over the place then you can disable it but i personally prefer to have it enabled all the time so what i like to do let's go back to what i like to do is in visual studio when i get all these errors and when i'm creating constructors it's just to do command uh dot in on mac and control dot in windows to create a constructor and since these fields are all final i can just say this is a const okay so what i also said we need to do is to make sure that this is a comparable object so that we can sort it what we want is for these for this sorting to happen in um in a reverse chronological order and so we can actually go and do that right now so let's go i have to look at a little bit of my notes um first we need to extend a comparable and then you have to create a function here so i can just do command dot again and that creates the override for me um now if i want this and here the other can actually be covariant of person because we're sure that the other object is also going to be a person what i like to do in this case is to i mean if you think about it if you want the order of the list to be chronological and that the ids appear in order of creation like zero on top one after that and two three then you would simply do um for instance id compared to other id this is chronological but if you want to make it uh reverse chronological or a greater idea if you're on top of the list [Music] compared to this id um so that's for the compare two um oh how come co-variant other can't call a non-constant superconstructor in the super class overwrite in comparable covariance other is it dark just being a little bit anger is it because we have to implement equitable as well so let's do that let's go ahead and say we are overriding um at override and then we say bull operator equally cool like this and then we say co-variant person a person other like this and the equality of two persons is very important how we actually implement this because maybe there is going to be two people with the same exact first and last name entered here but we cannot base the equality of the people based on their names because imagine that there were two food bars or food bases in this list or three or four if we built the equality based on their first name and last name if i tap on fubaz and actually say delete then all those food bases are going to be deleted from the database so that's not what we want what we want to do is just to assume that id is the primary key in the database you may even call it pk as django does or some other frameworks do but i've decided to use id so let's just say id is the primary key and two person objects are equal to each other as long as the id is the same so let's just say id is equal to other id okay i'm not sure why we're getting that error to be honest with you if i remove const weird so that's that and then what we also have to do is to overwrite hashcode if overwriting okay so let's overwrite hashcode as well um oh i see that's because i'm extending comparable i have to actually implement i i apologize uh implements we're actually implementing comparable not extending it so that's our bool operator equal equal let's create the hash code for the hash code we're gonna say it's the um ids hash code okay so that's that also we're gonna be printing just as a part of like debugging our application we're going to be printing instances of this person maybe so it's also a good uh thing to do to to override the tostring method so i think actually we can write to string and visual studio code helps with that yeah and in this case we're just going to say person id equal to dollar id first name is dollar first name and last name let's just do this one as well first name with capital n last name dollar last name okay so that's that's our person class so we have a good base here uh to oh it's performing hot reload and i have to go to the application for the hot reload to work so no errors so far it's working as expected i mean we haven't done anything special it's just the base class but um it's an important class it's one of the most important classes basically in this application so um now what we need to do is to look at how we can create instances of this person class um and what we could do is just to go here and then let's make these named parameters and i'm going to make them all required because they are required don't worry about the formatting the dark formatter is going to help us with that and i really like to place a little comma at the end of the last parameter so that when i press command s it's going to be formatted correctly if you don't do that then it's going to just be on one big line and i prefer it like this but it's just a preference so good now let's have a look at how we can actually create a database and put these objects inside that database all right so to do that you need to know a little bit about sqlite databases and there's a lot of material online that you can grab and have a look at but um so i'm not going to go into the exact details of how to create a sql database as such just to test with you could do that but what we're going to do here i'm just going to bring up something called db browser for sql lite and you can actually grab this for free from their website it's a program that is natively running here on this mac so um i'm just going to show you how we create a database here sqlite database on how the format of that the creation of the person's table is going to look like we could maybe just call it people actually so let's go in here and call this i can't even see the box on top that's unfortunate why uh oh here let's call it uh people people okay and we're gonna use it as a sequel light right now on my desktop and i'm just going to say save now let's say that we're going to call this let me see what we call it here people let's call the tab table people table people and we're then gonna go and we have three fields remember the id first name and last name so um the first field is gonna be an id and you can see here how it gets created we say it's an integer is a primary key nsai which is auto increment that's very important we don't want to increment the id ourselves so then the next field is going to be first name like this and is a string uh let's say text or don't they have string here okay but we can't enter a string anyways and then we're going to say it's not null n n alright and the next field is going to be last name and that one's also going to be a string and not null so this kind of text that you can see here is how we're going to create our database so it says create table people we're also going to actually say if not oh i can't change this but we're going to say if not exists because whenever we run our application from scratch we want to create the database if it doesn't exist and we want to create this table if it doesn't exist otherwise we just want to read from it so this is like the basic of how you create uh oh it's interesting how the format is working in here so this is the basic of how we're going to create this database uh so now that you know about that we can actually go to the flutter side and start working with our database and the connection to the database and there is a really good plugin i'm going to bring my browser here so let's go to pubdev and i'm going to go sqflight this is a really good plugin uh that allows you to work with sql-lite databases with higher with high-level functions so um it's it's it's very easy to use as we will see soon i will show you how to work with it just to create a simple crowd application uh so you don't have to worry about the details of that for now let's just go to the installing part and then grab this here i want to go to visual studio code to our terminal if i can see it i'm going to paste that all right okay um that part is done also um for us to be able to create this database we're gonna do that actually in the documents folder of um the application as you know in ios and android when you're creating an application each application has its own sandbox so inside the sandbox there are different directories that ios and android create by default such as documents directory library directory and temp directory etc and um to for us to be able to create our database inside the documents directory we actually have to have another package called a path provider so let's go and see if we can find it um here is a path provider it's actually a plug-in it's not a package sorry about that it's provided by flutterdev and it's got 100 popularity of course let's go to the installing and then grab that plug-in and bring it here okay and now if you look at our um let's have a look if you can find it pop spec yaml you can see that path providers here and sql flight is also here so we got those two things running let's go to our application to main dart if i can type it maybe i can't uh here what we need now is to be able to grab the path for our database so i'm going to have a look at my notes a little bit here and see what i've called it in the actual application so we can actually follow along so let's go in here i'm just going to place a void test uh async and i'm just gonna call it from the build function that's how i like to test stuff usually so let's see if i can grab the um path for the database so i'm gonna say directory is a weight there is a good function called get application documents directory and then we're going to say directory final db path or something like that or just path we call it and i'm going to call it um let's say directory okay dot path because this directory is i think is an object i've called io.directory or something like that uh yeah and directory i think is i o directory yeah and we don't want to actually get the object we want to get its path uh so we are gonna put this in curly brackets um and then also we're gonna say this is a slash uh db sequel light like this okay so i'm going to print this path and let's run the application and see how that looks like also hot reload is not going to work when you have added new plugins to your flutter applications so you may actually have to stop this and i sometimes you can get stuck with actually even that not working so i like to do flutter clean and then that's going to clean up everything all the caches and then i'm just gonna say flutter pop get okay and then i'm gonna say run without debugging let's see how that goes avoid print calls in production code that's actually pretty good winter that's telling us about that awesome okay let's see how this goes it's just a waiting game uh thankfully with flutter we don't have to do this so often and because we have hot reload and swift ui also is almost there jetpack compose yeah but if you're doing native development with just like native android and native ios it's um it can sometimes be very very tiresome to wait for these commands so here's the directory you see it's in documents directory in the applications sandbox you see application and the uid of our application in this case this application and then documents and then db sql so let's keep this as it is now what we're going to do is to start working with the creation of the database and also creation of the people table if it doesn't exist so for this i'm going to create actually a class so let's call this person db because the class is called person i'm actually going to fold this we don't need to see the entire thing and i'm going to fold this and fold this so we can focus unfold our imports as well so let's go and create a class here i'm going to say person db okay the person db one of its main absolute main components is that it has a stream controller um and i'm going to talk more about this as we go on but just know that the person db is going to expose some sort of a stream of person objects to its consumer which is going to be the home page and within this stream it's going to just give you an array of persons as you update delete add and read you're going to just work with the stream so it's very difficult to explain it just right away so let's just get started with creating a final string in here and say db name so we're actually going to ask the consumer of this class to pass a db name to us so i'm gonna say create constructor for final fields okay um then what we're gonna do in here is to work with a database object so a database object is defined i mean the database class itself is defined in uh sqflight so let's import that package as well so i can tell you sqflight here so if you go in here i think we should be able to find a database class can we find it open database here future database so this is an abstract class so when we work with a database we need to uh be able to hold on to a database object so that we can execute our queries on that so let's let's immediately do that so i'm going to say database and it's an optional for now uh and i'm just going to call it db all right so by default the database nil until you call an open function on our class so let's go and work with the open function so i'm going to say this is a future of bold this is how i like to do my futures usually i know that futures can actually produce an error but i really like to actually get the true or false in the future sometimes so that i know whether the operation went fine or not without having to do error handling on the consumption site so future bull in this case it means that it's either gonna succeed or fail with true or false okay uh so we're gonna do error handling inside this future itself and then i'm going to call this open so this gun is going to open the database and this is asynchronous um in here then we're going to say if we all we already have a database don't do anything let's just say true okay but otherwise we are going to continue uh with the code so in here then i'm going to save that grab that code from our home page that created the database path and let's remove the test function from here here okay final directory and a path and then in here we then say dollar db name which is available here is passed to us um then what we need to do is just let's do try and catch in here and then let's see and then we're just in this case we're just going to say print error is equal to dollar e and then return false now in the try we're going to do something that is gonna it may actually produce an error so that's why we have to try and catch in here um the command that you need to know about when working with sqf lite is open database so it's like this open database and there is a path for it and in here we have the path and you can see open database returns a future of database so let's just say final db is equal to weight and then then we're going to save that db itself like this remember this is our private instance of this db that we just retrieved from here now we're gonna create the table so i'm just gonna put some comments here and say create table and i'm going to say final create command is equal to or just create is equal to i like to use three single quotes like this and then we can put the entire create statement in here um like this people so we're gonna kind of do the same command that you saw in the sql like browser application with a little bit of different format it's gonna achieve the same thing um so i'm gonna put it here now the id field was an integer and it was primary key and it was auto increment excuse me and then we're going to have a first name field um and and you can see now why uh um air lens can be a bit annoying in that it kind of like it makes the scene a little bit angry looking even though there is no error but looking at it you will just get like ah get out of my way but if you can live with that that's fine then just go ahead with airlines first name is gonna be a string and not snow and we're gonna have last name um if i can spell it not snow all right we have the command let's execute this command and then create a database uh and then we can say sorry create a table so we say um so let's say a weight um after that is done we actually want to read so as soon as you open your database you want to read the entire contents of it and then place it inside some sort of an array so let's create an array in here and i'm actually going to call it i'm going to say this is a list of person um per um should we say people hmm yeah that could actually work maybe that's what i've done it that's how i've done it before as well or let's say persons like this okay um so let's now i mean we have the create command we've executed what does it say prefer const over final for decree okay const um now we've created the table if it doesn't exist um now what we need to do is to create a function that returns all the instances of person classes within our database within our table so um i'm going to go in here and create another function in here and i'm going to say future list of person what should we call it what have i called it before fetch people i think it's called here i'm going to say fetch people and we say this is async as well the goal of this is to be called actually from the open function so let's go in here and say read all existing person objects from the db then we say final persons is equal to a weight fetch people i'm using like persons and people and people interchangeably so you have to excuse me i just don't know which one to use really i'm just gonna say persons because this is called persons and i'm gonna then as soon as we read those we're gonna place it inside our um inside our uh array so i'm gonna say uh persons or what do we call uh i think we said uh let's see i have to look at my notes a little bit uh okay right so we need to then place these inside our person's object here here let's make this private as well so i'm then going to say okay persons is persons and and then i'm gonna um now now that we've done it i mean it's great now we've got a local copy of all the data that we've read from the database although we haven't actually done the reading we're going to take care of that soon but you also now need to know okay now that we got this data how are we going to give this data back to the home page and that is why you need a stream controller a stream controller is your gateway of having kind of like in rx swift you would call it a behavior subject uh in that it can actually terminate so it's not a behavior really but a stream controller is your gateway in containing a stream that is not only not only allowed for you to read from it from a consumption site but it's also allowed for you to write to it so it's not a read only source of data but it's also right so we're going to have to define a stream controller here so let's say a stream controller of an array sorry list of person because it's going to contain a list of person and we're going to call it a stream controller uh and this is actually gonna be a broadcast uh let's see if it allows us final stream controller why is it not happy about this because stream control i think is defined in async so let's import that it's now imported here as you can see import dart async so you need to do that as well unfold this so it's equal to broadcast okay and we're gonna do the broadcast stream controller because if you don't do that you will not be able to do hot reload in flutter because when you do hot reload your build the build function of your home page is going to be recalled and the stream is going to be subscribed to again like it's your your stream control stream builder is going to listen to the stream again and you can't do that because if you have one stream controller and you expose a stream method or stream properly to the outside world and once it gets subscribed to it can't get subscribed to again and that's when you need to do a broadcast so that between the hot reloads the build function will get called and then you will subscribe to the broadcasting of this stream controller again and that's just going to be fine so you're not going to run into problems in that case so the whole point now is that now that we got the persons what we need to do is to send that or add that to our controller so i'm going to say stream controller add persons okay and then return true so we did actually the um the opening of the database so the opening of the database we did the reading and then we added to the stream controller and and that was it really so to be honest with you we can get away we don't even have to have this intermediate value here i can just say persons like this right and then we get rid of that um okay let's have this print even though it's saying that it's it shouldn't be used in production so i'm gonna fold the open function for now let's focus on the fetch people functionality here and see how we're going to write that in the fetch people we are going to say um final db is equal to db because what we want to make sure of is that the database has been created before we come here and i'm going to say if db is null then return false okay now from this point on dart is uh oh return an empty or empty list a dart is intelligent enough to understand that since we've checked for null in here then db from this point on is not going to be i mean even though it says in here but we're going to be able to use it without a problem so it's it's going to understand that it's not null anymore so let's put a try and catch in here and i'm going to say catch e i'm going to say print error fetching people equal to dollar e return an empty list here and what we're going to do then in the try statement is execute a query which is a read query so i'm going to say final read is equal to db and await db.query and the query functionality is a little bit different from what we saw in the open functionality in that in here we just executed a raw statement with execute but in here sqlite has really good functionality that allows us to you can see the query it allows us to actually specify the table and what you actually want to grab from that table so as you will see in here i'm just going to say the table is what did we call the table was it people yes people i'm gonna go in here i'm gonna say the table is people let's see what other parameters we have in here this yeah there should be distinct objects and then there is a parameter called columns um so in columns what we're going to read is id a string here first name and last name okay and then we're going to order everything by the id id column [Music] that's our read functionality and you can see it returns a list of a map of string and object so so it's a list of a dictionary that with keys of type string and with values of optional objects so they may not have a value uh okay oops i um so let's go in here and somehow we need to create i mean we should get this um people or the read operation like this result needs to be transferred to a list of people or person class so if we ask every person class to be able to initialize itself from a map of string object then we can literally map this list to a list of persons so let's go to person uh person class here and then we are going to create a function in here and i'm going to say person from what should we call it from database uh something like that maybe person from rome maybe because that is actually a row right so i'm gonna say person from row and in here we're gonna actually get a map of string and object like this and i'm going to say row in here we're going to just say id is row id as int first name is row first name as string and then last name is equal to row last name as string okay so we got that now in place we have the firm row function um and that should be good to go what we need to do i'm going to fold the person class now and in here we have to map this i'm going to say final persons is um let me have a look if i call it persons here as well just so we can follow along people so it is all over the place with people and persons and uh person but that's okay then i'm gonna say read and then i'm gonna say map let's say this is a row r well let's just call it row then i'm going to say person from row of row like this and then we're going to convert it to a list to list now that we've done that we can store it um return people just like that [Music] so you see this was a simple fetch functionality and then we have yeah this is this is great as it is then because our you see there's two functions here one is open and then open actually does a read as well which does a fetch so this is the r part of our quad so this is the only thing we've taken care of opening the database and also reading its contents as you have an open function you also need to have a close function so let's just go and say future void close because we need to also close the database so let's just say if um db i want to actually see if i created the close function as a future of bull or future of void it's bull again so let's say bull uh in the close functionality you need to make sure that there is a database so we're gonna say final db is db we can actually grab it from the fetch here yeah let's grab it from here from the fetch people in the close i'm gonna say return false because there is no database to close and then we're gonna say db.close i think i think so but this is the future of void so let's await on it and then we're gonna say return true okay so now we have close as well um great this is working i'm just gonna do a hot restart here um now that we have a person db we also need to ensure that we can return um the list of persons that we fetched in here right so and that is why we have the stream controller uh but the stream control is uh private to this class so we from the consumer's perspective they're not interested in stream control they're interested in a stream so let's go and expose that so let let me go in here oops not in that function i'm going to go in here let's go like this i'm going to say is a stream of list of person class right and we're gonna call it all um and all this does is is a stream controllers uh stream like this so this this should actually do the trick for us it's it's not more code than that um but one thing that we are missing here is how we're sorting these objects because here we're just saying stream and then in here when we fetch the objects we're not actually sorting them and when we're adding them as well we're not sorting them so somewhere we have to sort these objects and it's not fair for the consumer to be to sort these things so let's go to our person db and in here in the stream let's map this value which is a list of persons i'm going to say persons and let's just say persons sort like this so this is going to return a sorted list of persons which in turn is going to call the compare two function and it's gonna sort them in reversed uh chronological order okay so now we got a simple person db what we need to do in our um homepage is to create a stream builder because we need we have a stream of persons and we need to just render them to the screen [Music] so i'm gonna bring up my notes a little bit just to make sure that i'm following along with what we've created before so um in here we also have to create our person db and i can see that this person db has a open and closed functionality and for that we kind of need a stateful widget so previously i said that we don't need it but it seems like we do let's convert this to a stateful widget so i'm going to say command dot and convert to stateful widget and in here i'm going to say final uh final quad storage is equal to uh what's it called person db uh with this with the capital b and i think there was a parameter as well right um db name or something db name yeah let's make this required it's a named required name parameter and then in here we say db name is db sqlite i'm kind of following a django convention here for my database feels good uh now that we have the crotch storage we have to open it upon instantiating this um initializing this uh oh yeah initializing this widget and also we have to close it upon it being disposed of so let's go to our init state let me see what am i doing here uh let's actually yeah let's go to init state and then i'm gonna place this pose in here um in in its state we can actually create it maybe as well so let's say fi a late final person db and crot storage in the init state we're gonna create it crud storage is that and then we're going to say a quad crotch storage um open i think we call it we don't have to wait on it because when it actually does open and reads all its data then the stream is gonna get populated so we don't have to await on it and you can't even do that in in its state anyways so on dispose then we're gonna say crotstorage.close i think we call it right okay that's for the opening and closing of the database i did a hot reload there it's just because it has a habit uh in the body let's start with um a stream builder i think we call it and its uh stream is gonna be our uh quad storage dot stream didn't we expose that or we called it all i think yeah all like this and the stream builder also has an actual builder parameter and in the building uh when we're actually making a making the build we have to make sure that we're listening to active and uh waiting snapshot states what is happening here is that as you create a stream controller and then there's data being flown into it then it can be in two states in in which you can read its data and those are active and waiting but if it's in any other snapshot state then you may want to display for instance a loading indicator so let's go in here and say switch snapshot connections missing case yeah and then we say case connection state active is going to do the same thing as connection state waiting and in here let's just say return text okay uh return const text and then in any other case which is default then we're gonna say oh my god what was that default we're going to say return constants center child circular progress indicator just like that okay do we have to do const on this as well no what did it say avoid cons keyword but if we avoid it here then it's gonna okay all right now you can see we got an okay here so that means that we got some data what it can also do in this case is just to make sure that there is data to be displayed so you can say if um connection state dot data if snapshot that data is uh null then we're gonna return exactly the same thing uh this loading indicator okay uh otherwise we are gonna create our list so this is the exciting part so let's grab the people let's say final people is equal to snapshot data as list of person and i'm just gonna for now printed uh people okay and i'm gonna do a hot reload let's see if we got any data we just got a circle loading there active waiting data is null okay let's print the connect is the snapshot here and see what is happening builder okay it says personnel no no okay and that could be because here when the when we call open let's go into the open and see what is happening uh create table if not exist okay stream controller add persons persons await fetch people i'm going to just print we are here and i can see that we're not actually getting there so um oh yeah we are here and there's an empty array actually it's working now yep uh on a just command s and yeah it's an empty array good it's an empty array of persons and that's kind of okay because we haven't added any objects to our to our database so uh we got this far now let's create a list basically so what i'm going to do here let's start with list view builder because now um yeah we probably need to actually start with listviewbuilder okay so i'm gonna i'm just gonna say list view uh return list view dot uh oh god i can't spell builder um before this i think there's a primary call item count or something and then this is equal to people count and there's an item or length or what's it called length yeah um and then either item builder item builder let's get some help from visual studio code like this for the item builder for now i'm just gonna say text can i do that uh hello const all right let's just say hello for now okay now it's a little bit strange right now because we've created the part of the application that reads all this data but we don't actually have any data in the database so what we could do is to start building this interface that we saw here where you can provide a first name and a last name in like some sort of a compose field so uh let's go and i'm gonna fold this whole uh home page and its states everything let's go and create i'm gonna fold this as well we don't need this so it's a little bit cleaner let's do a compose view all right i'm going to call it a stateless widget and is it a stateless widget it's probably a stateful widget because it has some controllers so so let's go and say sdf for stateful and we call it compose widgets now this compose widget it has two it should have two text editing controllers to keep track of the first name and the last name and there is a button here so this is a column widget so it has to have do those two let's go and say uh final um final not late final i would say lay oh my god laid final um text editing controller first name controller okay um what did i do nothing okay and then i want to say last name controller so these are going to hold on to the first name and last name all right i brought i mean this is not our application that we're developing but i just brought it up so that we can have a look at how it looks like and what we're actually developing so um let's go into its init state and initialize those so i'm gonna say first name controller is equal to text editing controller like that and copy paste and in here i'm just going to say last and in this pose let's dispose of our controllers first name controller dispose and last name controller as well dispose of it all right we got the text controller like the actual the text controller is in place that's the boring part let's go in here and let's actually grab this compose widget and bring it in to it's not hot reloading because we have to go to our application let's bring it into our home page so um let's go to the home page it's stateful widget homepage state here and let's change this list view builder to we we kind of need to have a column there so let's see let's put this inside a column command click is sorry command dot on mac or control dot on windows and then let's put it inside a column as the first widget we're just going to say a compose widget um okay const and now if i command s to hot reload i think we actually get some rendering issues because this list cannot be placed inside a another column so we have to kind of like create this inside of and expand it so wrap it with a widget of expanded and i'm going to clean the errors and then if i command s then the error is going to disappear now we have no items so that's why we can't see the list so now we have the compose widget so all we have to do is just to actually go and like to create the logic for this the main component or the main widget for this is going to be a column so in this column we're gonna create two text fields so um text field and the controller for the first one is gonna be first name controller and the next one is gonna be a last name controller and then there is going to be a button as we saw it's called add to list so let's go create a button here and we call it text button and its child is a text that says add to list and it's um oh the child should be the last item also you need to know unpressed we're going to get some callback here and in here we probably have to just say const and that is it so now you can see some stuff happening in here let's put this into padding so it looks a little bit better okay and then in here as you saw there was some hint that says enter first name enter last name so let's go and add these hints in here so these are the controllers and i think the hints it's in some sort of a decoration and then we say input decoration hint something hints text what is it is a string a hint text is a string yeah so we say enter first name okay and then god we have to say const as well so um position arguments const hint text oh this should be a cons sorry about that um so that's the decoration and then we have to have another decoration also for the other one that says enter last name uh let's grab this and put it here enter last name okay we gotta enter first name enter last name in here and then there's the add to list let's make this add to list a little bit bigger by adding a text style we say text style um font size let's say 30. great oh that's too big 25 maybe or 24 at least a little bit better kind of looks like this one yeah it's fine these are a little bit smaller i can see but that's okay enter first name and last name i don't think we have to adjust those you get the idea you can actually go and add those yourself now upon the user pressing the add to list function we at the moment have an empty function here but we kind of want to pass this first name and last name to whoever created us okay so let's define a typedef in here i'm going to say typedef on compose is equal to a void function that takes in a string first name and a string last name so this is just a callback definition and in this compose widget let's go and ask for this kind of a callback it's kind of like a void callback except it's not it has parameters so i'm gonna go and say final on compose on compose like this and i'm going to add it in here and i'm going to make it required so it becomes a required named parameter required like this all right now let's go to uh compose widget and then say uncompose and then we get help from visual studio code to complete this i'm just gonna say print first name uh print last name just like that uh what's your invalid constant value on compose uh avoid print calls in production uncompose but it doesn't have to be a constant though const compose with it do i have to remove that prefer declaration comes on immutable compose widget uh what is it complaining about uh invalid constant oh is it because yeah hmm strange okay um that was strange because compose widget is a constant initializer here so i don't know what that error was anyways we're printing the first name and last name in here and the goal here for us when you press the add to list we're gonna say um final first name is first name controller and then we're gonna say text and then uh final oh is this optional by the way no final last name is lastnamecontroller.txt and then i'm going to say uncompose or widgets on compose and let's call name pass first name and last name in there and then i think it would be really good if you actually cleared the text that's one thing i didn't do in this original because like if you say blah blah blah add to list these things stay here so let's clear those so let's say first name controller.txt is equal empty and then we say lastnamecontroller.txt is equal to empty now that we get that in place let's go to our application here uh let me save this uh what happened crowd example class compose try performing hot restart okay all right it's in place i'm gonna say foo and bar and you can see foo and bars being printed here because of our print statements so i think the compose widget is done that's why i'm gonna collapse it here or sorry yeah collapse it it's not expanding collapsing it now we got a first and last name what we have to do now is just to go to our database and add this as a person so what we need i'm going to fold this let's go to our person db and say a future a new future in here that says future create and then we'll say give us a string first name and a string of last name okay and this is gonna be future bull whether it's gonna succeed or not i think that's what we've done in the actual uh where i wrote this function in the beginning and yes and that it is uh that's the case and we have to do the same thing um as we did here we grab the database if it's present and in this case we return false and and we say try catch and then we say print error in creating a person is equal to dollar e return false um in the tri-state oh in the try statement we're gonna create the object and the creation is one of them my favorite ways actually a sql sqflight allows us to create objects using high order functions and it's really cool in that you can say db in this case and we say let's see insert and in here you provide your table and i think the table was people yeah um it would be good if you could like actually write this table name as a const but i haven't done that yet but you could do it would be better actually if you did that um and in here you provide your values just directly like this so um since id is auto increment do you remember when we did the uh open function here we said that the primary key the id is primary can auto-increment so we don't have to provide the id for it and the cool thing is that if you read the documentation for insert it actually says that um let's see if the documentation says insert what it returns the id of the last inserted row so that is perfect because once we get the id so we say final id then we can create an actual person object so because at the moment we just have a first name and last name we don't have the id and we're not gonna it's not cool to go and do a query because you can't go and query the database after first name and last name to get its id because there may be multiple objects with the same first name and last name so it's not gonna work that is why you get the id back so in here we're gonna say first name is first name and uh last name is last name like this um that is the id and we have to await on this because this is asynchronous and then we say final let's create since we have the id and first name and last name let's create the actual person we say person is a person like this i think named parameters id first name is first name last name is last name i like to place a comma at the end so that it breaks it down for me in multiple lines and now that we have the person we have to do two things insert it into the array of persons like this so we say uh person z add person and then we also have to then give this person to our stream controller so we say controller stream controller dot add persons now this is gonna be sent down the stream so it's really cool you will see it soon um and also we return true at the end okay so now i'm gonna go and fold this feature and then when you in our home page when you compose a new message in here instead of saying let's see no here on compose here then we're gonna go to our uh let's say a weight uh quad storage or what did we call it uh crud storage yeah across storage dot insert or do we call it add create for the crowd yeah create first so if i refresh i'm just gonna do a hot restart just in case and for the first name i'm gonna say foo and then bar and then add to list and you can see the text fields got cleared and then there's a hello here and that is because we're not actually creating tiles so let's go and create tiles for this object and then we're going to say return tile let me just make sure that i have the actual original code list tile um now for the list style uh i think we need to do a title and subtitle so i'm gonna say title the title is a what a widget so i'm gonna say text and we have the actual oh i see we have people here but we don't have the person so let's say final person is equal to people at that index and that that we say person first name and then for the subtitle i'm going to say it's a text that is equal to the person's last name okay let's see oh is it not subtitle it is subtitle all lower case if i can spell yeah and then this should be semi-colon at the end you see here's fubar printed here but if you looked at the original example my god what did i do if you if you looked at the original example the title was the full name so let's go to person and extend it so we say string get full name is equal to is a getter and it's equal to dollar first name and dollar last name okay uh and then we can fold this as well then we go here and then instead of text title first name we say text person full name and for the subtitle it will be equal to id you see we say id and then we actually print the person's person id like this so if i go back to our application and do a hot reload there we go all right i'm not gonna do the styling exactly as we did here because that's gonna take also a long time but you can do the styling later if you want to but we're just gonna get the data at the moment okay so that's that uh now we've taken care of um uh creating the tiles for each person i'm gonna say bads and i'm gonna say baz and then baz last name uh add to list and you can see baz baz last name last name anyways now if i tap on this person i want to or i want to have this x button as we saw in here for me to be able to close like delete this user so let's go and take care of that um and in order to do that we have to take care of like um a little accessory here which is called trailing so let's go to this tile and i'm going to say trailing and the trailing is going to be a text button and the child is going to be a text i'm sorry about that just one second the child is going to be a text and then the text is actually gonna have a text button child is gonna be i think an icon in this case uh icon uh if i can spell it and then it's gonna be icon data dot uh let's see what am i using i'm using i can see i can actually grab that code and bring it here so that we don't have to write it again so here's that icon text button parameter unpressed okay and then let's put the unpressed like this like this uh now you can see that we got that x button here i prefer const okay const um great great here as well perfect now we got the arm pressed in here as you press this we want to show a dialogue that looks like uh this boom are you sure you want to delete this item yes or no and this is just going to be a dialogue of true or false so let's go and develop it i'm going to go in here and i'm going to say future of bull show show delete dialogue async or no it's not async and i'm going to say return show dialog and then the contour let's get a build context in here build or just call it context that's the context and there's a builder let's call the builder in here like this and in here i'm going to say return alert dialogue there's actions content and in here for the content we're just going to say text are you sure you want to delete this item um and you can see now uh when we have aero lens then it's gonna get really like i don't even know what the problem is at this point prefer const okay cons there's so much information i prefer cons for the alert dialogue as well okay avoid conscience can't prefer console when it comes a value of type future dynamic okay and then we have to map this um oh sorry then and then we get the value and we say if value is bool return value else return false okay this is gonna take care of that last bit and for the actions uh we have a no and a delete so let's go actions like this and i'm gonna say text button uh what does it say no child is text and i'm gonna say and no here uh my god unpress is also required okay let's create a an empty unpressed here like this invalid const oh my god because this is not cons so let's remove the cons there prefer const jesus christ there's so much cons stuff everywhere cons to i don't i don't even know where i should put the cons to be honest with you uh actions uh invalid const value all right so if i remove the arm pressed here then it says it's required then i'm going to add the unpressed and it says invalid const value because because of what exactly let me remove this const and let that be as it is yeah let this oh and this one is a const my god there are so many lints i don't even know what i'm doing anymore um okay let's go and then there's a delete let's add the delete as well uh text button like this i'm gonna put here and then i'm gonna say child is delete god okay in here now we have to do navigator of context and then we pop not poop pop with true because we want to delete and in here we say false that's it i mean now we got the dialogue and now i'm gonna switch back to our application and upon pressing this button i'm gonna say this is now an async function and i'm gonna say final should delete is equal to show delete dialog with that context if should delete then we have to call make the deletion here uh wait now this is when we have to make the deletion let me just press this button and see if this dialog works are you sure i want to delete this item no okay let me put a print in here print should delete you will see now you will get true or false depending on whether the user says no or delete delete let's show the dialogue again delete is oh delete is false no we did it exactly the exact opposite this one which says no should be false sorry about that this one should be true so now if i press this and i say delete then it should be true okay now now that we've worked on that let's go to our let me fold this let's go to our person db and create the delete function okay so in here we're going to say we have a new future fold this as well let's say oops let me fold this sorry about that fold fold a little bit cleaner so this is c in crud c in crud and then we say d then future of bull delete in this case we don't want to delete with first mls and we don't want to really delete with an id because we don't want to expose how exactly this database is working so we just say delete a person so we say person person and oh async all right so when it comes to the deletion i'm just going to grab my notes sorry about that let's go and let's do the same thing as we did in uh we just want to make sure that there is a database set up like this uh okay then we say try catch e print deletion failed with error dollar e and return false and in here then we are going to say that we want to delete something so we say final delete count is a weight db.delete from a table that is called people and then there is um a where clause then we say id is equal to something and then where arcs and in here you say um person id so this is how you do deletion with a sql flight in that you pass your table name and then there were clause and then do the formatting in here so try not to do your formatting in here because then it could actually be broken and uh susceptible to sql injection so pass like you're formatting in here and then your arguments like i'm doing in here so then we say if we are expecting if we're deleting something by an id then we're expecting the deleted count to be exactly one because you can see this says um passing null will delete replace the returns the number of rows affected so we want to make sure there is only one row affected we say if deleted count is equal to one then we have to remove this object also from our person's ray uh we say remove person and then we say stream controller add persons and return true otherwise we say else return false now that we have this delete functionality let me just uh fold this let's go to our home page state upon deletion here where we added a to-do we have to make this yeah it is async actually i can see here let's make the deletion call we say if should delete then we say crud storage delete person and we await on it okay so let's delete bazbah's last nam and there we go that's working as well and we can delete this one as well and we say foo bar boom all right um one thing i notice is that uh also you this is something you may want to fix as we add an item to the list i can see that this focus is still on this text field you may want to refocus on this text field but i'll leave that to you now i think we've taken the c and the uh d so it's create and delete oh also we've taken a read we've taken care of the read so it's we've done everything so we've done crd it's the u that's remaining right it's the update and if you look at this application that we did here if you tap on it you can update it on it and we should create this dialog now so um let me fold this so it's not in the way let's go and next to this dialog show delete dialogue do a future of um what does it have to return it has to return a string um and it has to return sorry it's the first name and last name and for that to be honest with you we kind of have um we are already have on compose so i wanna i wanna kinda see how we've done it in the how i've done it in my notes um yes so this actually returns a person so let's take care of that so if uh if you if you save you give it a person basically you give this function a person if you save it gives you that person back with the updated first name and last name and the id is gonna stay the same so um and if you say cancel then this is gonna return a nail to you so let's say show update dialog and then we get a build context and then we say context and we say person person so we wanna update this person okay then sorry context and here we kind of want to say return a show dialog and we say in here show dialogue builder is that how we did it in here as well show dialogue builder yeah and we say context is context and the builder let's get some help from visual studio code the builder looks like this return alert dialog and let's get the content in there the content is a text and it says enter your updated values here okay and then in here we have to also say then value if value is person return the value uh else return null okay um now we have the content we also have to get the actions uh no actually the content i can see here the content is a column so there's a text and then two text fields so let's create two um text field like controllers so let's say what do we call them text editing controller first name controller i'm gonna do it like this final uh is equal to this and then final last name controller is text editing controller like this and then i'm going to go in here and then say alert dialog for the content i'm going to wrap this into column and then we need also two text fields so i'm going to say text field um do they have any default value their default value is actually the person's first name and last name so in here we have to say first name controller text is person first name and then last name controller text is person's last name okay now that we've done that then we go and create a text field and we say controller is a first name controller and we create another text field here as well which is the last name so text field and then we say last name sorry about that last name controller now we also need two actions in there um let's go and create our actions uh or this sorry this is in the column this is not where we're going to create the actions we're going to create actions the alert dialogue so let's say actions um and there are two buttons cancel text button uh child or sorry unpressed and then there's a child and the child says text cancel and then there is another one text button that says save okay const if that makes you happy and in here we just say a final edited person is equal to a person uh oh sorry this is cancelled so we say navigator uh off context you can't see what i'm typing and then we pop with a null value in here because yeah that's what we said in our contract here that's for cancel but if you save then we say here's edited person is equal to id is person id but first name is first name controller dot text and last name is last name controller dot text right uh that's the edited person and then we're gonna pop the navigator with this so i'm just gonna say uh navigator of context pop with the editor edited ted person okay so we got that working hot reload isn't working because i'm not in our app i'm gonna go back to the app so now hot reload is working uh let's go and show this update when you tap on the tile and that's in the home page um let's see we're creating a tile and then let's say on tap how does it look like it looks like this oops let's create this and then i'm going to say this is an async function and i'm going to say final edited person is equal to show edit uh display or show it was show edit right show update dialogue sorry about that and the context on a person and then we say if edited person is not null then in here we actually have to um go to our database and say update that person so let's go to the database and say we have a feature here that says future bool and then we say update person how do we do it we say update a person original person updated like this so we take the original person and update it with that okay so and i think that's if i look at my notes i think that's how we've uh how i've done it before as well i'm sorry but i'll just there's a quick look here in my notes just to make sure that's how we've done it in the other place as well now i see that we're taking a person so what we're doing in here it seems like it that we're taking the idea of this person and updating that person's uh first name and last name so i id never gets updated so let's do that let's go to this delete and grab the header we need a database so let's make sure that the database is there like this then we say try and then we say catch e print failed to update person error is equal to e and then we return false in here um for the update we have to tell the database to do this we say db dot update and that also takes the table we say people and the values are going to be a person sorry first name is gonna be the person first name and then last name last name is equal to person last name um so that's for the update uh also the update is very similar to the other formats in that we have a where clause so we say id should be equal to this person's id so we say where arcs equal to person sorry an array of pers or a list of values okay that's the update the return of it is a future of int and what does it say does it say um is a number of uh what does it say returns the number of changes made number of changes made hmm i think it's the number of rows that were affected by this update so let's say final update count is equal to a weight and then we say if update count is equal to 1 let's now update our local storage then in this case we say persons remove where uh person uh or sorry other then we say other id is equal to this person id so this is the removal of that person from our local storage and not even storage really it's just like a local array that we have then we say um stream controller uh oh sorry after the update we actually have to insert the new one so we say persons add um and when we say person's ad then we have to insert this new person right i think so and then we say streams controller stream control sorry about that add persons and then we return true good now that we have the update also in place i'm gonna fold this let's go in here and in there edited person we just say await crowd storage dot update person or let's just say edit it that's it so the argument type future awaits uh if async what is it complaining about the argument future blah blah edited person oh we didn't await on this sorry about that um now we should do now this should be good to go uh now let me tap on foo bar and just say oh this is yeah this is because this column let's go where we're displaying the show update dialog we have a column uh this should have a main access size main access size main axis size i think there's a min in here and let's do this let me just do a refresh here then uh i kind of probably need to look a little bit in my notes but that should really work what does it say restart application and non null value must be returned since the return type bull doesn't allow not in the update function so let's go into the update and see where i've mis messed up that's return and in here we say return false sorry about that as well um all over the place right now uh i'll do a hot restart here and let's go and tap on foo bar and that's mean worked actually so i'm just going to say foose bar and say press save and that's it really that's the conclusion of this video because if you look at our person demo sorry person database this is a seeing crowd this is the d for our crowd operation and then we have close open open is kind of like sorry this fresh is our r so c i'm gonna bring him in kind of like an order so we can actually oh my jesus christ what happened here let me grab it like this so c c r and uh r and then update we have as well which is the u in uh crud so i'm gonna bring it up here like this see our i mean this is not important you don't have to do this i just want to do it for the sake of the code looking a little bit prettier and then we say this is you so you like this like this c are you where did the delete go did i delete the delete that can't be true yeah i think i may have deleted it but you know what i'm not gonna i'm not gonna play with it it can be like this you get the idea c r u and then the d so you can play with this you can delete items as you want and you can see you can insert values in here without a problem delete update so um i would say that this is working as expected so i will place the code for this because this is quite a lot of code i think we coded about 400 yeah 436 447 lines of code um there's a lot of stuff happening in here and i hope that you got some information from it at least you learned something from it um and if you have any questions do let me know i'll be more than glad to help you so that's it for this video thank you
Info
Channel: Vandad Nahavandipoor
Views: 10,436
Rating: undefined out of 5
Keywords: flutter, flutterdev, dev, ios, android, crud, create, read, update, delete, stream, streamcontroller, future, database, db, sqlite, sqflite, query, 2021, tutorial, column, showDialog, AlertDialog, dart, dartlang
Id: kEUo98kqRzs
Channel Id: undefined
Length: 94min 28sec (5668 seconds)
Published: Sat Oct 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.