Flutter TDD Clean Architecture Course [14] – User Interface

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the time for putting all of our previous work into practice is finally here this part will be all about building the UI and splitting it into multiple readable and maintainable widgets hello welcome to ring so coder where you are getting prepared for real app development by building better faster more stable apps so subscribe and hit the bell if you want to grow your coding skills the UI we currently have in our number trivia app is just default increment a counter example but what we are going to have at the end of this last part is the following which you've already seen in the first part of this tutorial course so we will have a text field with two buttons and then a message text and we can input a number here and then we're going to have an error text displayed at the top containing the number itself and then the actual trivia text will be below it and of course we can also get random trivia and it's going to do the same and actually this text here is also scrollable and be sure to check out the written tutorial from the link in the description where you can also find all of the code written in this video and overall go through this lesson at your own pace we are going to create a new page under the features number trivia pages folder so let's create a new file call it number to be a page start and let's just create a blank version of it for now and then later on we are going to add stuff to it so let's create stateless widget number trivia page of course we need to import material i npm import floater material and we are now going to return a container but rather a scaffold and let's just for now setup an ad bar on it which will have a title text which will say number trivia so now comes the time when we change what's happening inside main dot dart from the default counter app to our own page so let's actually just delete everything which is currently present inside main that dart apart from the main function of course and we're going to create a new material app which will say of course let's just delete this import and main I'm using awesome footer snippets if you're wondering and if you wanna know which extensions for vs code you should definitely use as a fara developer check out the video from the card in the corner we're gonna return the material app from it with the scaffold not specified right over here but we are going to say number trivia page will be the home of our material app so this is the page which we have just created a while ago let's game board it and let's change the name here to say number trivia now I have launched the app so this is how it currently looks like let's add some theming to this material a bit of course it's going to be reso coder style theming so it's gonna be the green color so theme let's set it to theme data and let's just set the primary color to be colors that green and let's make it shade 800 we could also make something like 800 it's gonna be the same but let's just set it to shade that's more exponent explanatory and then also we're going to have accent color which will be colors that green and let's set this one to shade 600 and with that we can move on to the number trivia page in clean architecture the only communication pathway between UI widgets and the rest of the app is the presentation logic holder and in our case the presentation logic holder is a block but of course I'm not going to stop beating the dead horse and say that you can use any other state management solution out there where it's mob X Redux change notifier with a regular provider whatever you can use it completely fine with clean architecture because it's not dependent on your state management solution the presentation logic holder is basically a trivial thing once you get the rest of the air architecture correct but regardless of your preferred state management method you still need to provide your presentation logic holder throughout the whole widget tree and for that obviously we're gonna use the provider package but since we are using block which is actually integrated with provider and you can check out the tutorial dealing with that from the cart in the corner we're going to use a special block provider which have some nice block specific features in addition to the app bar a scaffold can also have a body and we want to provide the block over to the body and to all of the other childhoods which are going to be instantiated inside that body so let's say block provider actually we can use a snippet coming from the extension of vs code so let's import flutter block inside this builder function we're going to just return the block which should be provided down the widget tree from this block provider actually we do not need the context so we can just make it an underscore and the block which we want to provide is obviously the number trivia block but we're not going to instantiate like this because that is completely wrong since we need to provide dependencies and all of that that's precisely why we have registered all of our classes and their dependencies in the injection container file right over here so now we want to this registered instance Factory we are going to call this factory from within our number trivia page which is going to resolve in turn all of its dependencies and it's going to kick off the resolving of all of these like this whole dependency tree we can do that by calling SL which is actually from the injection container file and we're going to just specify number trivia block to be the type which we want to get over here and with that all of the dependencies will be also resolved before reacting to States emitted by the number trivia block and you know there can be empty which is currently being emitted the empty state then there is the loading state then load ed which is going to grant us the number trivia which we are interested in and finally there is the error state which we're going to handle by displaying an error message before doing all of that let's first build out a basic UI outline using placeholder widgets so the root of the UI will be a padded and centered column if we take a look at that it's a column because we need to have this top half and the bottom half because the top half is concerned with output to the user so it's going to output some text and the bottom half is concerned with input it's going to have a text field and also the search button and the random button so we're going to first replicate that with placeholders let's just first extract the body of the scaffold into its own method so we're going to say build body so the child which we are going to have here will be a column and this column will have children which will be a container which will represent the top half of the screen so the stuff where the messages are displayed and the number of trivia is displayed so this container will have to have a fixed size a fixed height to be precise if we take a look at that no matter how long the number trivia is for example if it can scroll or even if it's shorter so it can not scroll the bottom half stays at the same place and we are still inside a column and for that we need to fix the height of the top half of this display of messages because otherwise the bottom half would start jumping around for example now it would be a bit more downward it would be pushed downward because naturally without fixing the height of this top half container the longer text of the trivia would try to expand the container to fit its content so because of that we're going to fix the height of the container and let's just fix it to be the third of the size of the screen so we're going to say media query of context which we can't did not have inside build body so we're actually going to pass in context context and of course it's build context and let's just pass in context to build body invocation from the body of the scaffold so now we want to get size of course and its height and divided by three so it's going to be the third of the size of the whole screen and now the child will be only a placeholder so it will look something like this of course we do not want it to be flush with the top of the screen under the app bar so let's just provide some sort of a padding in the form of a size box so size box height or FS set H I have an extension or vs code it's called water widget snippets so if you want that just install this extension in vs code and with that you're gonna be able to use those short cuts so the height should be 10 of course after we provide a comma here it's going to be pushed a bit downward after this we want to have an error sized box with height of 20 because now comes the bottom half of the screen sort of which will be concerned with the user input so this will contain all the text input fields and the buttons so it's going to be another column this one will not have a fixed height because the height will not be variable it will have just three widgets inside of there and it needs to be a column because we need to stack the text input field and the buttons below each other and then the buttons will be inside the row of course so let's do just that we're now going to implement it only with placeholders but of course we're going to change that later bottom half and let's put a column in here which will have children and those children will be a text field which currently will be only a placeholder but because this placeholder would not be constrained otherwise it would just overflow this whole thing we need to provide a fallback height but just set it to 40 so now it's going to sort of represent the text field now for the next widget present inside this column it will be a size box so f SZ h the high will be 10 and with that we have a size box over here below which we are going to place those two buttons and because they are besides each other we're gonna place them inside a row so this row will also have children and now there are going to be placeholders again and we're again going to need to fix their height to be 30 for example so let's try and look how it looks like and it's definitely not looking any good it overflows and the whole button is sort of unbounded because it's only a placeholder let's just try to add in our placeholder besides it and even if we fix their width so for fallback width will be I know maybe 100 is a good width for the button or maybe 200 mm but 200 all right and we would do the same thing for the other placeholder it's not a good way to do things even with the real buttons we will now want to specify there with manually we want to let them expand to whatever width they want to be and also to whatever height they want to be so for that we're now going to specify fallback width but instead do something robe specific we're going to wrap these placeholders which represent buttons so the same thing which applies to placeholders will also apply to buttons later on in this part so we're going to wrap them with a new widget and that way will be expanded we want to do the same thing with the bottom button which will be for the random trivia so wrap with a new widget expand it and with that after we provide commas here so that it's nicely formatted it's going to be looking good without any overflow and now an error sized box but this time for width and the size of the box will be 10 so we're gonna have 10 logical pixels in between the buttons but still this whole column is now looking great because it's flush with the sides of the screen so we want to provide some padding so we're gonna add banning the petting will be not 8:10 and now we cannot see it because we are using placeholders but later on we can have some problems that the contents of the column is children will be on the left side so that just to be safe Center this whole padding so we're going to say Center with it and now this outline of the UI with placeholders is finished let's now deal with the top half and then we are going to move over to the inputs in the bottom half so inside this top half instead of having a placeholder we'll want to react to different states emitted from the number trivia block and according to the state which is currently present we will want to display different UI so for example loading state will display a progress indicator error state will display an error message and so on so building out different widgets according to the current state which is present in the block is possible with block builder so instead of this placeholder let's add a block builder which is actually also a snippet coming from the extension block for vs code and over here we need to specify our number trivia block and also the state so number trivia state so let's actually import the barrel file for our block o and of course we do not want to put this into the container but we want to make this block builder to be the widget wrapping in the container so the top half will be comprised of the block builder which from it will return the container with the fixed height so let's just replay replace this default container with that one and now the child will of course still be only placeholder we're going to fix it later this let's put a placeholder here so that we can reformat the code so nothing's changed yet but we're going to get better soon and now we are inside a builder method of the block builder which provides us with a state and to react to the type of the state emitted from the block we're going to do some simple type checking so if state is empty which is the default stay which is currently actually present then we want to return a container which will simply say text and over there we are going to say start searching all right now of course this text is not looking great but we can see that it works in the state the initial state of the block is indeed empty this thing here is already becoming quite messy so let's refactor it by extracting the container into its own widget we're going to call it message display and this message display which is now present at the bottom of the file will be a status widget but it's not always going to say start searching so instead of providing a hard-coded string in here which still would work by the way but instead of this we want to have a string message so final string message and we're going to pass that into the constructor so add required this dot message and with that we're going to display the message and passing start searching has the message from of course it's not working because data is no self of course so we need to pass that message over to the message display and now it's going to work all right now let's actually style this message a bit we do not want it to be just this small we want it to be a bit bigger so we're going to set the style which will be a text style containing only font size which will be set to 25 all right and let's just make it aligned so text a line to be Center you could see that it moved a bit to the left not by much but it did move and also to make this text scrollable when it's a bit longer we are going to wrap this whole text inside a single child scroll view so let's wrap with a new widget single child scroll view and now if the message becomes a bit longer so that it doesn't fit into that third of the screen height which we specified right over here it's going to be scroll in addition to that let's just wrap this single child scroll view inside Center just to make it also centered on the vertical axis and now we are cool and this message display does not need to only display the start searching message when the state is empty but also if an error is emitted from the block so if state is error we can also display the error message so we're going to say again return message display and it is now going to say start searching but instead it's going to say state which is now casted smart casted into being an error which contains a message so now if the user inputs ABC which is not a number we're going to return the failure invalid input failure and that is going to be propagated through the block into a nice message being displayed now technically we could use the message display even for the state being loaded so else if state is loaded we could use that message display of course and passing to the state that trivia which is the number trivia dot text but we also want to display the number nicely as you can see in the example app we want to display the number at the top so because of that we cannot just use message display even for displaying the loaded State we're going to handle it a bit differently for now let's just leave this loaded Clause empty we're going to get to that later first though let's handle the load ding state so else if state is a low ding in that case we just simply want to display a circular progress indicator so let's immediately put it into a loading widget let's extract that we're actually going to just copy the message display widget because still even the circular progress indicator needs to have a fixed height otherwise the bottom half would start jumping around because of the changing height of the top half so we're going to just copy that message display below let's just call it loading widget let's rename that instructor it's now going to accept any arguments apart from the key which we can leave in there and of course it's now going to be scroll ball but it's still going to have a fixed height to be the third of the height of the screen and the child will be simply circular progress indicator and now we can use this loading widget and instantiate it over in the loading State so return loading widget now let's go on to displaying the actual trivia which is the most important part of the app we're going to create a new widget trivia display so what's actually again just copy message display paste it all the way down we're going to call it trivia display so let's change all of that and of course the constructor parameter will be number trivia which is the entity so let's import the entity let's just call it number trivia and make it be able to be passed into the constructor so number trivia the height will still be fixed but instead of returning just the single child scroll view we are in addition going to also return it inside a column with the number being on the top like this so the message will still be displayed and the message in this case will be coming from number trivia dot text but in addition to that we're going to wrap this whole thing this Center widget inside a column so wrap with a column and now the first children or the first child to be a grammar Olli correct will be a text and this text will contain only the number of the number trivia so number trivia that number of cord will convert it to string and then the style which will be text style will have font size of 50 so it's going to be two times as large as the message the trivia and then we're also going to specify the font weight which will be font weight that bold and with that we've just basically added a bolded text above the message which is also present inside the message display widget but let's actually test and see how the UI looks like right now so we are going to just always return the trivia display from the top of the Builder and just specify a made up number trivia so we're just going to specify number to be 1 or 12 and the text will be ABC just for testing purposes of course or let's actually make it a bit longer so we're going to say start searching start searching and paste it over here multiple times I know it looks Horan dysley but let's just test it so we have just created number trivia and we are always returning this trivia display so what's gonna happen is that the bottom overflowed by 36 pixels why is that even happening since inside the trivia display we are wrapping the text inside single child scroll view right well yes but in addition to all of this because we are now inside a column an additional column in addition to the main column which holds the bottom half at the top half of the screen we have a nested column basically and to make this Center which contains the text view only take up an appropriate part of the screen and not to overflow we need to wrap the center inside expand it so let's wrap with a new widget expand it and now all the overflow will be gone because this expanded widget will calculate the appropriate size in this case height of the child widget which is the text which it should take up so that it doesn't overflow its container and in this case the container is a column or I should probably now use the term container because that's a widget but I hope you know what I'm talking about it's not going to just overflow the column with the expanded widget all right so now we can stop testing with just made-up trivia and instead we're going to return trivia display I'll just ring the wheels oh and this trivia display will be returned from the loaded State so if it's loaded was returned trivia display and specify the number trivia to be coming from state dot trivia all right so with that we have the top half completely implemented and of course you can get all of this code from the written tutorial from the link in the video description and go over it at your own pace and over there there's also the whole project and github available so alright we've already done a lot to keep these widgets maintainable by extracting them into their own classes but there is one more thing which we can do and that is to add them into their own files so that the number trivia page that the dart file will not become just one long mess so let's do just that right now we already have the widgets folder created from the first part inside the presentation folder so let's create a new file and we're gonna create new files for every single widget which there is so let's start off with the message display the dart and while we are added let's also create all of the other files so it will be trivial display the dart and similarly let's just use the advanced new file extension so we're going to create loading widget the dart so this is created here and also we're going to create a barrel file so that we can import all of the widgets from these widgets folder in this one import so let's create widgets dart and now let's first export all of the other files from the barrel file so loading widget will be exported then also export the message display and export the trivia display and with that the barrel file is done for now and now we're just going to grab the message display from the number trivia page right over here we're just gonna grab it cut it out and put it over to the message display the dart after we import material so let's do just that now we have message to display done we can close it off similar thing will happen with the loading widget let's cut it paste it into loading widget dark after importing material done and finally the trivia display widget will be also extracted so we can immediately see that the numbered trivia page is becoming more manageable so let's paste it into trivial display after we import material and also of course we need to import number trivia entity with that we can now come to number trivia page and hit ctrl + dot and import only the barrel file which is that dart and that in turn will import all of the needed widgets so we are importing only the Barrow file now for the bottom half which is going to receive input because we are using block we are going to dispatch events whenever a button is pressed because we are gonna be using a text field which needs to hold some local widget stayed in order to function properly let's right now even extract the bottom half into its own widget let's just call it trivia controls so let's change this from a stateless widget to be a stateful widget because it's going to hold some local state because of that text field that's because we are gonna need to store the string present inside the text field as a state variable so let's create string input string and let's replace this first placeholder with the actual text field now the text fields work in a way that we are going to provide an unchanged callback which is going to grant us a value present inside a text field and when this is called we are going to simply store the value to change string value present inside the text field inside input string which we are going to use from the button presses all right and after hard restart the text field is visible in the UI but it's looking pretty horrendous Lee in my opinion so let's add some styling in the form of decoration so the decoration will be input decoration and we're just going to set the border to be outline input border so it's not going to have underline but instead an outline so immediately it's going to look much nicer and let's just also specify some hint to the user what he should do with this text field so we're going to say input a number cool but this apart from the bottom being overflow which we are going to fix next there is also another problem and that is that we can also input ABC even from the keyboard we want this keyboard to be only numeric and for that we are going to set the keyboard type to be text input type and that number with options but which is number will suffice and now we can see that we can only input numbers let's now move on to the buttons they're gonna be very simple still they're gonna be wrapped inside expanded but instead of being a placeholder it will be simply a raised button containing a child text search for this a string and then the color of the first button will be coming from the theme so theme of the context and it will be the accent color so it's going to be this nice green of course this is going to only pop up once we override unpressed because otherwise is disabled so now we can see that it works and of course the text theme should be displaying white texts so we're going to say button text team that primary what's that going to do is that the text will be white there are also other ways to change the text color but this is the simplest one here and now inside impressed we're going to want to dispatch an event to the block but we're going to come to that later let's just for now focus on the next race button which will be for the random number so let's copy and paste and instead of the placeholder we're going to say get random trivia it's color will now be accent so it's going to be just regular number nothing fancy or regular button I'm already going crazy with all these numbers and from unpressed we are going to want to dispatch the concrete event or the random event respectively but just to make it more clean we're going to extract that functionality into their own methods so we're going to create void dispatch concrete which will simply call black provider and black provider is an inherited widget and just like with any provider we need to get it from the context of the widget and of course we need to specify the type which we want to get so the type of the block which we want to get is number trivia block of course with lowercase R and with that we now have the instance of number trivia block and on and we can dispatch an event and that event will be get trivia for concrete number and here we were gonna pass in the number string and that's cool because if this was an integer we currently have only a string here and we would need to perform the conversion from a string to an integer and also the validation that it's not negative integer inside this widget layer and that's not a good practice you should never put logic into your widgets that's why we have that input converter class which is going to handle the conversion for us and here which is passing the string so input string will not care how it's converted over here we're just dealing with the raw data with the raw input data with the string all right so now let's specify this patch concrete to be the function being called from unpressed of the first raised button and with that shall we test if this works of course there's some minor bugs in here but let's just ignore them for now but when we input a number it will be stored inside this input string and we hit search we see the number trivia so that's cool but wouldn't it be nicer if this number got cleared up after we search for it because now we input one two three search and it still stays there so if we want to input another number we need to delete it and input a new one and that's not a good user experience so what we can do for that we need to clear the text field and this can only happen when we have a text control so we're going to create final controller and it's gonna be equal to new instance of text editing controller and now we can specify this controller on this text field we no longer need this comment actually so the controller will be our controller coming from the class and now before dispatching the event over here we're going to call controller dot clear and with that after we input a number one to search it's gonna be cleared automatically all right now let's move on to get trivia for random numbers so we're going to have to dispatch random let's just copy it below this function this patch random will be its name and here we're just going to change it trivia for concrete number to get trivia for n the number which doesn't take any arguments of course and we're going to call it from the unpressed of the random button but also it would be nice that in addition to pressing the search button we will also initiate the search with this check mark which currently does not happen so in order to for this check mark on the keyboard directly to work we are going to what's going on here we are going to override another property on the text field which will be on submit or unsubmitted so unsubmitted which takes in a value but we actually do not need it because all we want to do here is to call this patch concrete which gets the value from the stored input string and with that we can now test it so if we hit this button on the keyboard it's going to search for the number we can also still hit the search button and also we can now get random trivia so that's cool but still there is a problem because the bottom is overflowed by 57 pixels whenever the keyboard pops up we can fix this pretty simply by wrapping the whole body so this built body of the number trivia page we're going to wrap this inside single-channel scroll view and now when that's done we can input a number and the UI will move a bit up but also in addition to all of that let's just fix this horrendously long number trivia page again by moving trivia controls over to its own file so let's just copy or actually cut them out or together with their methods so let's subtract that cut it out and we're going to create a new file under widgets called trivia controls that dart import material and paste that over there we're going to also need to import flutter block then also our own block so block dart the Barrow file so that we can also use the events without importing any additional stuff and with that we can now add these trivia controls over to the barrel file to export trivia controls and now number trivia page already imports the widgets barrel file so that's cool we also have access to trivia controls and with that after we just do hard riff star to be safe we can now input the number still 12 goes there 42 those there again for it to with the search button works get random Namie trivia works and with that we have just successfully implemented this whole number trivia app with clean architecture so in these 14 parts of the clean architecture course we've gone from an idea to a work in app and you learned how to architecture apps into independent layers how to do test-driven development discover the power of contracts you dependency injection and much much more so the number trivia app we've built maybe on the simpler side when it comes to its functionality but what's important though is that there are the principles which are present in every single app which you build with clean architecture because what you learnt in this course is applicable to all kinds of circumstances and I truly believe that you are now an overall better developer because of this course so practice the principles you learned here and build something awesome with them right to go through this tutorial at your own pace once again and to get all of the code and all of these widgets and extract the widgets check out the written tutorial available from the link in the description where there is also a link to the github repository containing the finished project and if you don't want to miss more tutorials and courses like this definitely subscribe to this channel I also joined a notification squad by hitting the bell button to make sure you grow your flutter skills because here on resew coder I am determined to provide you with the best abdomen tutorials and resources out there if this video and also this whole clean architecture test-driven development course helps you give this video well I can also share it with other people our developers who will surely benefit from it too leave a comment if you have anything to say any suggestions or questions or anything else and see you in the next [Music]
Info
Channel: Reso Coder
Views: 15,108
Rating: undefined out of 5
Keywords: resocoder, tutorial, programming, code, programming tutorial, clean architecture, software development, flutter clean ui, flutter clean architecture, flutter clean code, flutter testing tutorial, flutter tdd, flutter test driven development, flutter crash course, flutter course, flutter, flutter tutorial, flutter dependency injection, flutter state management, flutter bloc library, flutter unit test, flutter mvp, flutter mvvm, dependency injection
Id: G-R-1rzR3zw
Channel Id: undefined
Length: 45min 24sec (2724 seconds)
Published: Tue Oct 29 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.