Transcript for:
Flutter Crash Course Overview

Hey everyone, my name is Nick Manning and I'm a Flutter engineer. So I create Flutter apps in my free time and I kind of also create tutorial videos about it. So I am the creator of fluttercrashcourse.com. Thanks very much to freecodecamp.org for sponsoring this video and let's get started. Hey everyone, my name is Nick Manning and this is my Flutter crash course. So I'm really excited to offer this to you because I've taken about six or eight months of filming and content creation and I've boiled it down into this course. And what it's meant to do is save you time learning Flutter. So what you see here is my show notes and as every video I'm going to do, I'm going to walk through my show notes so you can read along and take notes on your own. And I'm going to start with this one. In terms of my background, I've been writing software for about 20 years, five of those as an iOS engineer. So to follow along, some of you might not want to follow along, you just want to watch, that's fine. But you're going to need everything that the Flutter website says. So any kind of main operating system, popular operating system, latest version of Flutter, and an iOS simulator or Android emulator. So make sure you have that installed and all set up. If you want to, if you don't know how to set that up, you're having problems, you can go to my website or the YouTube channel that I have. And I have specific videos on how to set up Flutter step by step for Windows and OS X. So experience level required. So you need to have experience with one existing programming language and also something that you've coded like a website or a web app or. even a mobile app, you don't need to, but something that you've done in the past, so that you know, some basic programming, you have some basic programming skills. So let's get started here. If you want to, again, go see other videos, check out flutter crash course.com. But we're going to now start our first lesson, which is chapter one, which is creating a basic screen. So stay tuned. Hey, everyone. So in this lesson, we're going to cover layout in flutter. So we're going to be using a widget called column. And what column does, it lets us lay out widgets from top to bottom. So let me show you what we're going to be eventually coding. This is the location detail screen of our app. It's called the tourism co app. And the location detail screen shows a number of things. And you can tell that we can use this column widget because things are widgets here are laid out from top to bottom. So there's another widget called the row and row lets you layout stuff from left to right, for example. So, but you're pretty much most of the time going to use this column widget because a lot of content on a mobile app is all is, is a column style layout. So in this video, we're going to cover implementing three text sections. So text sections, let us define the area for, let's say, let's say we want to show summary, and then this snippet of text. That's what a text section will be. So let's get coding. So last time we have this, we left off with this home page, and we're going to rename it to location detail. So let's do that really quick. And name this directory location detail, because that's the convention of the code order organization we're going to use. So we have a number of screens, and each directory is the name of the screen. And then... the name of the file, the main file that defines that screen is also that name. So let's define that. And I'm going to now stop my app and restart it, I can't use the hot reload because I am changing the file name. So sometimes we can't use hot reload. So while that's starting, let's go over column. So I'm going to render three text sections. But I'm not going to just display text, I'm going to display colored boxes. So colored boxes are going to show us how that content is the bounding areas for each piece of content. So one way we can define a colored box is using a widget in Flutter called container. So container is kind of like the div of Flutter. It's a div in HTML is just a bounding area that's flexible. You have different parameters you can define. One of those parameters is color. So I can just say container and define some color. I can use a property called decoration. So. There's different types of decorations. One is a box decoration. It's just a generic way to define a box of some sort. And I can style that box using the color parameter. So I'm going to say color, and I'm going to say colors.red. So this in Dart means colors.red. Red is a static member, meaning you don't need to instantiate the colors class to refer to it. So that's why you have className. and then the value here. So lastly, container will take a child. So we're going to say child text, and then whatever. And then we're going to save it. And one thing we didn't do is define our column forgot to do that. So column has a parameter called children and children is an it's a list. It's not a single widget. So and it is a list because you can have multiple items in your list. So we're going to define three containers here. So I'm going to just copy and paste this, and one's going to be red, one's going to have a background of green, and one is going to have a background of blue. Now nothing's happening here because we want to define some parameters here. I can define some text, that's fine, I'll just do that real quick. But you know, look at the screen. I mean, nothing really is happening that's interesting. It's just defining these little tiny boxes here. You can't even see the text. So what I want to do is define something called main axis alignment. And what main axis alignment does is it lets us control how each child is vertically spaced on the screen or how it's laid out. And when I say vertically, for column it's vertically. So main axis is something generic. So I'll take a step back. So main axis is the main axis of the widget that you're using. So if you're using a column, the main axis will be a vertical line on the screen from top to bottom. If you're using the row widgets, the main axis will be a horizontal line from left to right. So the main axis says something that's loosely defined. And it depends on the widget that you're using so so the main axis alignment controls how content is laid out on From top to bottom I have the following options I have Space evenly, so let's try that I'll just go ahead and you'll see that the each box is spaced evenly on the screen pretty simple I can also say let's say end so if I say end Each item will be rendered from the very bottom of my column. And column occupies the entire screen. There's other options I don't need to cover right now, but the most common one is start. So we're going to stick to that. The second parameter for column or row, we're not going to cover row in this video, but it's also a parameter for row, is cross-axis alignment. And cross-axis alignment is the exact opposite of the main axis. It's the kind of the kind of virtual horizontal line on the screen. So if the main axis goes from top to bottom, the cross axis goes from left to right on the screen. And let me show you what options you have here. So I have cross axis alignment, baseline, center, and start stretch. So we're not going to cover all of these but one of the most common ones is stretch. So it's making sure that each item of my column is stretched from left to right. So let's save that. And I'll show you now, each item is stretched from left to right. And cool. Um, that's it. So this code looks pretty ugly. But at least we have some containers where we can store text. So once we do continue on implementing this screen, we'll have a nice bounding area and Content will flow nicely from top to bottom and it'll also be stretched. So let's clean up the code. That's the last step of this video and Since these are reasonable kind of pieces of code here. We're gonna make this into a widget. So I'm gonna take the Template of this file like all the import the class here the build method and I'm gonna copy it and I'm gonna create a new file called text section So the reason why we're defining the file here in the location detail screen is because we're not going to reuse this widget we're going to define anywhere else in the app. So we can keep it local. to this screen. So we're going to paste this in. And we have a nice template for our stateless widget we're going to build, which is defining a text section, we're going to name it like that. And then in the location detail screen, I can copy or cut the content we want to show. And I'm going to say container. And I'm going to say return here. And now we can just update this. So we can say text section. And we can define let's say, let's say three of these it later, it's going to be dynamic based on the types of text sections that we have. But for now, we'll just define a finite list. And we're going to say import text section. Cool. So this defines three red boxes pretty useless. So what we want to be able to do is for now customize the background color, even though we're not going to use it in our final screen, this background color property, I just want to show you how you can define parameters. So how to parameterize a stateless widget or really any widget. So if we want to pass in a color, First off, I define a private member. Private meaning it shouldn't be accessed outside of this widget. It's just something that this widget should know about. And to do that, I say the type of member it is, which is a color. And I have an underscore for the name of the member because that underscore means that it's going to be private. So I'm going to say color. And to customize it, I'm going to create a custom constructor. So a constructor lets me customize how I instantiate this class. So I'm going to say text section, because that's the name of the class. This is how you define a constructor. And well, what I could do is there's there's two types of parameters for constructors. There's an in Dart, there's optional parameters, and there's named parameters. So uh optional names ones and positional sorry so we're going to find to keep it simple positional parameters meaning if i say color here um you know we all will basically how we use it is in location detail i'm going to say colors red colors green and colors.blue. And it's positional meaning, based on the, you know, this is the first argument, it knows that it's going to associate it with this parameter simple. And then I can say this dot underscore color equals color. So this means it's kind of like same thing in JavaScript, where this means it's referring to the instance of this class. So I'm going to say this underscore color, and it's going to give me the value of that parameter, it's going to assign it to that. So in Dart, there's a shortcut to this, this positional parameter, and I don't have to define the method body here. I can just say this dot underscore color. And what that does is for a positional parameter, it's going to take that value and it's just going to automatically make an assignment to the member here, this value. So whatever I pass in as the first argument here, it's going to assign immediately to this dot color. So that's pretty cool. So finally, we're going to refer to our member here. So it's customized. We're going to hit save and let's see what happens here. Cool. It worked. What else we want to cover? Yeah, that's positional glamour. I mean, the last thing that you should do is say that this private member is final. And what final means is that Once you set it, you can't change it. And that's really nice because it makes anyone reading the code know that they shouldn't change it. They can't because the compiler will give you an error. And we don't need to change it after that assignment's been made. So I just say final here, and that's just like a best practice. So that's it. Later, we're going to add some real text. We're going to style it. We're going to see now how the layout is defining. how the text is constrained. But for now, it's pretty simple. And I hope you have a good idea of main axis lamb and cross axis alignment. And if you want to do like some bonus work changes to a row and try that out, or play out with the different options you have here. So let's continue on. Hey, everyone. So in this video, we're going to cover how to add images to your app. And it's pretty simple. There's two main ways to do it. One is to use an image asset or a URL of an image. So in this video we're going to first import an actual image asset like a file like a JPEG file to our app and we're going to include it in our pubspec.yaml file and then we're going to implement it. Later we're going to pull the image from a URL so this should be pretty simple but we're going to cover some things you probably don't know about yet like constraints and how to layout the image. So in the last video we covered layout. Let's just kind of cover what we're going to go over and implement in the whole video series. So it's this detail page with a nice banner image at the top and some text sections. So what we've done is we've laid the groundwork for the text sessions. It just shows some lines which we will implement in the next video with the text and all the formatting. But for now let's add an image to the top and keep it simple. So to add an image, we're going to be basically going through the blog post for this video. So if you want to look at the notes, I will be showing the notes as we go along so you can read along. We're going to create a new directory called assets images. So assets is anything like font files, images, any anything of that sort. And they're all going to be in one directory. So that's how we're going to organize things. And we're going to use JPEGs. And yeah, that's it. So you can follow along if you want to check out this branch of the code, or you can code from step two on your own. So what I'm going to do is off to the side here, I have an image already that I'm going to copy. And the image I'm going to copy, if you check out step three of the code, anything from step three onward has this image. So I'm just going to copy it here. And it's off screen here. you're not going to see it. But I'm going to copy it to the following directory. So in my code here, I have my main root directory. So I'm going to hit this button at the top new folder, and I'm going to create a new folder in the root of the project called assets. Oops, let me move here. So assets is going to be alongside the Android directory and the iOS directory. And then I'm going to create a new folder called images. And we'll have other folders there later. And then off in the video, I'm going to in another screen here, I'm just copying the actual actual image file. So I'm getting it from my code on branch on the branch that I have at the repo, the link to the repo is here in the blog post. And it's in step three. So I've already copied it. And let me show you the fact that it is copied. So since this is a tourism app, it's going to be of all Japanese locations. Just I just decided to pick that randomly. So this is a location in Japan. And this is the image file. So later, we're going to load it from a server. So now that I have my images there, I can't just use it straight away, I have to go into my pub spec YAML file. And let me hide the code here. And so the pubsql YAML file is like a configuration for your project. It's in the root of the project, you can see the file name there. And you get to list like what packages you're going to use and all of that. We haven't added any packages yet, we will get to that in another video. But if you scroll down here, you'll see that there's some example configurations you can enable. So in Dart to comment something out, they use this pound symbol, right? This number symbol here. So if you just comment it out, you'll actually be able to use that config. And so the important part is to configure this correctly so that it'll work or else if the formatting is messed up, it may not work. So what we're going to do is say, it says here in the description to add assets to your application, add an assets section. So- we have to have this line here, and it has to be indented properly. So the parent of this is flutter. And then assets is here. So it's indented by it's indented here. So like that, you can't do this has to be like this. And then we're not going to include specific images, we're going to just include the entire directory. So we're going to say, for all the assets we're using, we're going to say what the path to the actual images directory is and and that is assets slash images, and then make sure to include the slash at the end. That way, Flutter knows that you can include all the images there. So it's going to look like this, this is the blog post, you can see the notes, we're going to want it looking like this. Another gotcha is you want to make sure that this is indented as well. So the actual directive here is indented properly. So we're going to save that. And then let's implement the actual image. So let's see, we have the code here. So last time, we have our we had our location detail screen. So this location detail screen had just three text sections, we're going to fill that out in the next video. But we're going to want to do is add an actual image banner at the top of the screen. So it's going to be one of our children of our column. So let's add that now. Let me look at what we want to do here. So because we want this to be its own widget, we're going to create a new widget the same way we like we created the text section widget. So I'm going to call this new widget, image banner. So this is a widget we're going to create in just a second. And before we even implement it, we're going to just code how we want to customize it. So what do we want to pass in to the instantiation of this widget, which is only basically the file name. So that's what we're going to do, we're going to say, include the path to the image. So we're going to say assets. slash images slash, and then the name of the file, it's kind of weird, because it's Japanese, of course. So if you don't speak Japanese, it'll look weird to you. But that's the name of the file. That's the name, that's going to be the name of our location when we show the text, corresponding text with that image. And note that later, we're going to change this app to be dynamic. So we're not going to hard code the image, we're going to pull it from a web service API, right? For now, we're just going to hard code it to just get it to work. So next, we're going to include the widget that we haven't even implemented yet. And I'm just doing this for brevity here. So I'm going to say image underscore banner. So that's going to be the name of the file we're about to create. Remember that in darts, if you don't know already, the import should be in alphabetical order. So I'm going to make sure that this is before this. And that it's underlined red because we haven't created it yet. So let's create it now. We're going to go into our location detail folder here. And because this widget is only going to be used by location detail, we're not going to have it live anywhere else. It's a widget that's local to location detail. If it was shared across the app, we would put it in a separate place. So let's call the let's name the file the same name of the widget image underscore banner. and make sure it's all lowercase. And then since this is a stateless widget, and we're going to implement it much like we did the text section widget we did in the last video. So I'm just going to copy this code here just as a template. And note that Visual Studio Code also gives you some options. And there's extensions to kind of use a hotkey to auto generate a stateless widget really quickly. But that's not what we're not going to cover that. that's something more advanced. So let's name it to our image banner. And this is the name of our widget here. And what we're not going to want to customize the color. But what we're going to do is be able to customize the path to the asset. So we're going to have a private member here. And it's going to be a string called asset path. So it's private again, because there's an underscore here. Second, we're going to pass in asset path. So this is going to be a positional parameter to our constructor. So that means that when the person wants to use this widget, the first argument they provide to the constructor will be the asset path. And this dart, if you didn't follow this in the last video, when we use this positional parameter, and we use this dot, and then the name of our private member, it automatically assigns the value. So really quick, if you didn't see it last time, if we just have something like this, this would be the long way of doing it. So this asset path, asset path. So this is kind of the long way of doing it, but we can't work, this is just better to do it this way. So let's implement our image banner now. So What we're going to do is we're going to display use the flutter widget, the image widget, but we're going to wrap it in a container. What that allows us to do is provide some other options like padding or the height and all that. So you're going to want to wrap your images in a container or some other widget like that. So let's get started on that. So there's going to be, if you look at the screenshot, there's going to be a certain height to the image. So we're going to want to expand the image all the way from two. to the maximum it can go in the container, but we want to still constrain the container of the image to a specific height. And to do that, we're going to use something called constraints. And that's a parameter on the container widget. And much like decoration that you know, there's also something called, you know, there's box decoration, but there's also box constraints. And what box constraints does is it lets us provide all these other options for how it the content in that container is constrained. So the most common named constructor for this is called expand. And what that does is it says, let me expand everything, all the content in my container, as long as the height stays at 200 pixels. So to specify the height in flutter, or Dart, we're going to use a double and a double is a certain data type, you could see it here, that just basically it has a decimal point. That's all. That's all you have to know. So you can say 200 like this, but sometimes the Visual Studio code will give you a warning. You can also do it like this, but using a decimal, like a proper decimal, even if it's.0 is probably better. And that's constraint. So we'll see how it works in a second. But constraints is going to say, expand all the content until the height is 200. We're going to have a decoration. And we're going to give it a decoration of a background color. We've already covered this in the other video. And we're going to just say gray here. The reason why we're giving the container a background color is because later when we load it from a URL, if that URL fails to load the image, we still want to show some kind of placeholder, not just white space. So that's just a decision I made. You don't have to do that. So the child now is going to be the image widget. So we just say image. And to use the image widget, we're going to use also a named constructor. And remember, a named constructor is goes like the name of the widget, and then dot and then the name of that constructor. So there's, as you can see here, there's different ways to name the use that different named with constructors you can use one of them's asset, which we're going to use, there's also file memory and network. So we'll use network later. Let's use asset for now. That's basically taking any asset you've specified in your pubspec.yml file. So we can now just provide it the name of the asset path. So I'm going to say asset path. And the last thing we want to cover in this video, last main thing, is how the image wants to expand and behave based on the screen size or the container that it's in. So much like HTML or CSS, you can specify how it expands and all that. And the way you do that in flutter is we use this fits parameter. And we use this kind of value called box fit cover. So box fit like box decoration box can constraints. Box fit gives you additional options like that. So fit height fit with cover fill contain, you can use these in your free time and click into them and read about them. in the documentation, the documentation will explain how to use these. But in this video, we're just going to use cover. And what cover does is it fills the image all the way as much as it can within the container that it's in. Cool, they have something similar in CSS as well. So let's save this. There's some syntax error. So we're going to make sure that we have the image asset finished here, and then the container finished. and let's see what else we didn't. Okay, like go like this, make sure this is finished. And what else I need a semicolon here. That's what it was the semicolon. So I'm going to restart it. And there we go. The image loads and it's exactly 200 pixels high. And now we can get started on the text of our app. So That was the tutorial here. And if again, if you want to read through the blog post, it has all the code. And you can read through it in your free time. And yeah, that's it. So thanks for watching. Hey everyone, so in this video we're going to be covering how to use custom fonts in Flutter and we're going to be building out our screen here where we already added the image at the top but we're going to start adding text sections here. So a text section will have, as you see here where it says summary, it'll have a title and it'll have a body. So we're going to implement that widget and then we're finally going to cover text theming in Flutter. So text theming allows you to define all your style in one place for different types of elements in your app. And then that way your code is very clean, because it knows what kind of style to pull from. So let's get started. If you want to follow along, I have the blog post here. And to get the font files that we're going to be using those font assets, simply check out step slash step 04 branch of this, the code repository, and the link is in the blog post. So let's get started. We're gonna implement first, we're not going to quite follow step by step the blog post in the blog posts order, we're just going to implement the actual text section first, because then I can apply the font and it'll just look like nicer, it'll be more understandable. So the first thing we're going to do is implement more features of this text section, because right now it's very contrived, it just shows colors, that's it. What we want to do is remove this color and be able to show a title and a body. So let's implement that now. So instead of color, we're going to implement two private members. One is title, and one is body, we're going to update the constructor and update this. So this dot body, so whatever you pass it in, pass in here as a positional parameters will be assigned to these members. And then let's basically define how we want our widget to be structured. So this each widget can have its own layout. So in the location detail screen, we do use something called a column where we already covered that in the layout video. But each text section will have its own column because content is laid out from top to bottom in a column format. So it's going to be summary and then this body of text. So instead of container here, let's implement a column, and it's going to be its own column. Main axis alignment is going to be start meaning the each child is going to be laid out from top to bottom, sequentially without any padding, cross axis alignment will be stretch. So I want it to stretch to the full width of the container. What we're going to do is remove decoration, we don't need that. And for child, I'm going to have some text here. Well, we have to say children because it's going to be a column and it's going to be a list of items here. And we're just going to have title. And then the other one is body. Then we're going to end our column. Now we already did here and and our children here. hit save. And then we're going to there's an error because we have to update our location detail screen to use this. So we already have text section imported here, we don't need to do that. And now we're just going to say, we'll hardcodes and values in here. So we're going to say summary, something one, and then something two, and then something three. So later, we're going to make all this text dynamic, it's going to pull from a web server API. API running on a web server somewhere. And we're not going to hard code anything like the image names and all that. So cool, it looks really boring, because there's no formatting to it. So let's cover that next. First thing we want to do is add padding to each of our widgets. So to add padding to each text bit of text here, we're going to wrap each text widget in a container widget, the container widget lets us define that. that the text doesn't. So to add padding to a container, because we want to control the different padding schemes, so we want to control padding on the left and right and the top and bottom, and it's going to be different for each, we're going to say const, which is a constant edge insets. And then from LTRB. So that's a special named constructor for edge insets, and it lets you granularly define all that padding. So because this each this text section widget is going to share the same left and right padding, I'm going to for simplicity sake, define a constant up here. And it's well, it's not, it's going to be a static constant. And I'll get to that why it has to be static in a second. But we're going to call it horizontal padding. And for just brevity, because I use this a lot, I'm going to say h pad, and people usually will figure out what that means. The reason why it's static is because since I'm using a const here, it just has to be static, I can't I can't, you see, if I remove it here, I can't define a constant as a as a member of a class here, it has to be static. That's just rules of Dart. So for the left and the right padding, it's going to have that value. For the top and the bottom, I'm just going to use a custom value. So I'm going to use 32. And for you don't really need to specify the decimal point, but I just like to because it's a double and just more consistent that way. So then we define the padding here, I'm going to end, let's see text and and my container. And then I'm going to add, let me add my child. And then I'm going to add the other container. And it's just going to have different padding because of because of the fact that it's a just based on the design of the app, it's going to have different type of padding. So that padding will be let me look at my notes, it's going to be 10. And just use the same value as horizontal padding here, save it. So cool. Now we have the things like nicely padded. And I'll add some more text here. So you could see it like kind of looking a little more realistic. In the next video, we're going to add in real text here. So let me just paste that in. Cool. So that's just really, really ugly looking text. But it shows you that it's going to flow nicely and the padding looks okay. Okay, so let's cover the style of the app. before we do that, though, the style that we're going to implement uses a custom font. And so we can't implement that style without it failing until we add our font file. So let's go add a custom font. So to get the custom font file, we're going to need and let me show you the screenshot that the font looks really nice. It's this font Montserrat. I'm going to I've checked out the step four branch of the code, and I'm just going to copy the assets that already have, I'm going to do that off screen here, because it's just easier. And what we're going to do is in the assets directory, we're going to have a child called fonts. So that's going to be a sibling of the images directory. And then I'm going to just paste it in here off screen, and boom, okay, so the fonts got added. So each font file, I downloaded these from Google Fonts, each font file has a special like family name. And what we're going to do is in our pub spec YAML file, as you remember, the pubs YAML file lets you define packages that we're going to cover that what we haven't used the custom package yet. It lets you define where your image assets are. So here assets slash images. But for this video, I've implemented this already, which you're going to have to type in yourself or copy from the example code. We can define a section called fonts, and it has to be indented properly. So you just do one indentation because it lives under the flutter section. That's very important. We're going to call it Montserrat. So the family name you define here is the family name you'll refer to in your style when you define styles. So for each font file, I can specify the weight I want to use. So for this file, it's going to be 300, which is kind of like regular light slash regular weight, and then 600 is kind of a bold weight. So we're going to have two different weights. So make sure you save that. And the indentation is all proper. It's like using two spaces for each section. That's how YAML the format YAML is defining indentation. So how do we use these fonts? Well, one thing we can do is in our text section, we can define in each text widget. just to get something to work, we can just say style. And then we can define text style. And then we can define all kinds of parameters for that style. But for just for cleaner, simpler code, we don't need to do that verbose way of doing things, because that's going to get very repetitive. What we want to do is to find one single style throughout the app. And it kind of works like CSS as well. And to define the style throughout the app, because we're using a material app widget. The Material App widget gives us these shortcuts. And one thing, let me look at my notes here. One thing we can do here is define something called a theme. So this is how we use themes in Flutter. So a theme is something general, and there's different types of theme. So we're going to say theme, and then theme data. And theme data lets us define various how various widgets are styled in the app. So the first thing we're going to define is the app bar theme. So the app bar is is a material design terminology for the navigation bar at the top. So for iOS users, it's called the navigation bar. So we say app bar theme, and you instantiate an app bar theme class, exactly. And so that app or theme class is going to give you certain parameters. One is the just basic text theme of the navigation bar at the top. So let's define a text theme. And the text theme we instantiate here. And for the title of that text theme, there's different, there's different options you can use for text theme, you can go over it in your free time. But these are the different, these are basically all the main options for a general text theme. And I won't get into this too much. But for the sake of brevity in this video, I'm going to find the text theme that I want to use. And instead of hard coding it into my file here, I'm going to define the text theme in a separate file. So it's nicely organized. But for now, I'm just going to type in what I want to implement. And that's going to be app bar text style, this is going to be something I define as a custom thing. In just a moment, I'm going to now I'm going to implement it. So to organize your style properly, what I personally typically do is I create a file called style dot dart. And that style that dart is going to define all the style in my app. And what I'm going to do is import material. And I'm going to define some constants at the top, because I'm just going to paste it in here. And what this does, it lets me keep my style file very succinct and clear. So I'm defining specific different categories of text sizes. And then the name of the font I want to use this is the core family name I defined in my pubspec.yml file. So I'm going to paste this in here, this is going to be my app bar style, it's going to be it again, it's a text style. And it works again, it works a lot like CSS. So it's very easy to follow it has a font family. So refers to my font name Montserrat a weight. So for font weights, in Flutter, you can define different font weights. So they all go from 100 to 900. And because I defined one that's called 300 in my pub spec YAML file, see here, I can use that weight. So that's the font weight. And then the font size, it's medium, it's 20. And then the colors, it's just going to be kind of white because the fact that I have a colored nav bar up here. So I'm going to save that. and then I'm going to import it in my app dot dart, style dot dart, I'm going to save it. And cool. Now our nav bar is styled with the custom font, you see it's kind of like lightweight here. And we'll we'll style it more later. Because that's not this is not quite the final design we want to use. But we'll we'll continue with this later. So let's finish up the style of our app. So Now that we have the app bar theme, the indentation is a bit strange looking here because of the way it auto formats it. But let me do this so that you can read it better. And the last style we're going to define here is our style for just basically the text section. So I'm going to go look at my notes here. So for the text theme, we're going to define, there's various text theme. that throughout the app that we can define here. So text theme could be for various different components. So one is for just to lose something loosely named called title, you can I'll show you how to use it in a second. But it's basically for any title you use. So we're going to call it a title textile, we're going to implement this in a second, because this style same with the app bar textile will come from our style file. And then we're going to say body one. So body one is just another name we're going to refer to later in our code. And that's for any body text body style, we're gonna call it body one text style. So let's implement this now in our style file. So in our style dot dart, I'm going to paste these in first off, I'm going to paste in the title text style. And the title text style is going to be looking like the same thing but it's just going to have a black color and it's going to be large. The next one is body one textile, same thing, but it's just going to have a different text size. So body text size of 16. So now that I pasted those in, and I have these defined here, the general style for all the text in the app now is changed. So it's going to use the basic font of the style. But there's certain elements about it that are not going to be used. So for, let's say, the title text style, it's not going to use certain elements of this. So it's not going to be large yet. So to kind of deliberately say, hey, for this title here, let's say summary one, I want to use the title text style, I have to deliberately go into my text section widget. And we're going to have to update that. So how we're going to update that, is for here, we're going to say for the text widget style, and then we're going to say theme, use the name constructor of, we're going to pass it our context. And again, our context is something we pass around in the app. And it just is a way for Flutter to kind of know certain, certain contextual information about the rendering tree, the widget tree. And now we can refer to any style that we have defined here. So we can refer to text style, text theme rather. So because of the fact we defined a text theme, I'll go back to here, here. So in our theme data widget here, we defined a text theme. So now we can use it. So I can say theme of context, text theme. And now I can specify exactly what subset of my text theme. So because I defined a title text theme, again, going back to app dot dart, see I defined a title, text theme, I can use that now. So I say title here, and I'm going to save it. And now it's using the actual text theme I wanted. It's the exact text size that I wanted to use all along, I'm going to do the same thing for my body. So I'm going to paste this in here. And I'm going to say body one. So basically, it's not going to be, I don't have to do this, because it's already taking the style of that, because this is just normal text. If I define a text theme of body one, all the just general text of the app is going to be styled like this. But I'm still defining this style here. And I'm using explicitly body one, because it's just more explicit that way it's clear. And but you don't have to do it like that. So yeah, that's, that's how you style text in Flutter. I think that wraps it up for this lesson. Yeah, and we're gonna just, you know, style this more later. And in the next episode, we're going to actually use dynamic text. So we're not going to hard code anything in. But yeah, that's it. So thanks for watching. Hey, everyone, Nick here. So in this episode, we're going to talk about three things. One is how to use models to represent data and functionality. And we're going to update our code to make our screens dynamic and not hard code any data in there. And also we're going to be covering Dart concepts such as generics, the map function, anonymous functions, and cascades. So if you want to follow along, I'm going to be going through this blog post as I go through the lesson. And you can find the blog post on fluttercrashcourse.com and then go down to the episode working with models here. If you want the code, the link's in the blog post right here. You have to just check out this branch here I have highlighted to actually have the code. we're going to be implementing. So let's talk about the significance of the an apps data model. So a data model is something very, very generic to any kind of app. It's not only Flutter apps, it could be a web app, just a traditional software application, or it could be a mobile app doesn't matter. So a model is basically a glorified class in darts. So when we have an app that we're going to write, the app usually has input and output. So like any software program, so the input of the data is going to be probably some data we fetch from an API somewhere. So it could be a Firebase API or a normal traditional HTTP based restful API. So that's the input to our app because the data is coming into our app. But the problem is we need to when we take that data into our app, we need to represent it somehow in memory. And that data might be complex, it might have different types of data with different types of fields to it and properties. And also that data might relate to each other in different ways. So Let's say we have our tourism and co app here, the input of the data would be a list of locations that can be shown to the user. And each location can have a list of facts of that location, like fun, interesting things that you want to show to the user. So if we want to represent that data in our app, we're going to create two classes, a location class and a location fact class. And we're going to have a relationship between them. So The model also represents the relationships between different pieces of data. So the location model or class, if you will, will have a list item, a member that's a list, a dart list, that's going to be a list of facts. So there's a one to many relationship between location and location fact. So all of this data taxonomy and all that stuff we're going to represent in classes and we're going to call them models. That's just like a terminology that. a lot of people use. So when we fetch the data from the API, we're going to write certain code that creates instances of the location class. And when we want to use that data in our app, let's say we load a given screen, let's say we load a location detail screen, we can easily work with that data if we have them cleanly separated into separate model files. So again, scrolling down here. We have the models location and location fact that we're going to create in the lesson. And again, it's going to be a one-to-many relationship. So that's more coming from database design terminology, one-to-many and all that stuff. But that's just like stuff that you should know as well. You could use that not only for databases, but also for how your models relate to each other in your Flutter app. So this is how we're going to use our models. I'm scrolling down here. This is how... It just shows the... given use case of how we're going to use our models. So our app loads. And then since we don't have multiple screens yet in our app, we're going to do that in the next lesson, we have a single location detail screen, it's going to load, we're going to say, hey, just give me like from a list of given locations, based on a location identifier or ID, we're going to also add that in this lesson, give us the name of the location, and then render it in the navigation bar. And then For each location fact, again, it's a one to many relationship between location location fact, render a given text section on our screen. So right now, as you can see, in my simulator, I have three text sections, that's just hard coded. So what we're going to do is update the code to render a given text session based on each fact we have associated with that it could be one fact, it could be five facts, it depends on the location instance, we're rendering. So how do we add our models? So basically, I'm going to show you the best practices for when you're adding models, where to add them, and also how you can use code commenting and what the best practices are to make sure that if anyone else is reading the code that it's easy to read. So let's get started. The code example that we're going to code is in this blog post. So I am going to open my... Basically, I'm going to open my code here. And I'm going to explore here. And I'm going to create a directory called models. So basically, in terms of code organization, best practices, in the lib directory, there's going to be a sibling directory to screens, the screens directory that we have, and we're going to call it models, then we're going to create a new file called location dot dark. And now we can increase the size, we can just implement our location model. So it's going to be again, a class. And each class and dart is going to be in title case, meaning the first initial of every word is going to be capitalized. And I'm going to have three fields here, I'm going to have string, I'm going to a location has a given name, it's going to be, let's see image pass. And then it's going to be a list of location facts, final list location fact, and I haven't created that yet. So it's going to have an error here, facts. And then I'm going to update a constructor so that I can create this model very easily. So we've gone over this before, but we're going to use a shortcut here, where if we use this dot name, this dot image path, and this dot facts, we can the constructor will automatically assign the values you pass in to your members. And that way, we don't have to actually implement the class like the constructor like this. And we've gone over this previously, so I won't go over that too much. And then we're going to import which a file we haven't created yet. Location fact dot dark, make sure that the name of your model is in single case like a location because it is one given location. So don't make it plural. And also that goes for the file name. So I'm going to create a file name called location fact, not facts or anything like that. It's a one single fact, and a location fact, again, title case, let's see what we want. It's going to have title and a text, let me just paste this in because it's faster from the blog post. It's not rocket science here. So a location facts going to have title and a text. And that's really it. So no errors are here. That's great. Um, so yeah, let's see. So let's talk about how we're going to add business logic to our model. So business logic, again, is just a glorified term for just some code. And there's some rules to that code based on your business or your what you're trying to accomplish. So we're going to implement that. And one traditional way to implement business logic is you can add them to the model directly, if it's not such a big app. If it's kind of a small to medium size app, a lot of people just add the business logic and core functionality to their model. So let's say I want to get a list of locations. I'm going to add a method that fetches those locations. And I'm going to add that method to the location class. So that's pretty much a common approach. So in this method here, I'm going to implement that. it's going to I'm going to paste this in, because there's a lot of code here. And I, I suggest you not typing it in because it's it's tedious, you can just check out the code here. Let's go through this. So this is going to be a function that's static and and static meaning, you don't have to instantiate location to invoke the function, you can just say fetch all. So this is going to be a function called fetch all, it's going to fetch all the locations in our virtual database, it's hard coded now. But in a few lessons, we're going to fetch it from an actual backend API. So we're going to say fetch all. And this is not a realistic fetch all function, because usually you would add like, you know, pagination parameters, a fetch from one to 10, or whatever, or fetch numbers 10 to 20, or all that. But this is very trivial example, and it's going to return a list of locations. So each location we're going to call is the constructor. we're going to pass in a name here. And this is the path to the image and all these. And then it's going to be a list. And for each list item, we're going to instantiate a location fact. So this is going to be summary how to get there, etc. So it's really ugly now. But once we have an actual web service API hooked up, it'll this will all go away. And also note that for now, we are using this kind of ordered parameters for our constructors. There's there's, if you're having a lot of parameters, that's there's another way of doing that we'll cover in another lesson. But for now, this is like the simplest way. Great. So we have our models, let's continue. So let's make our code dynamic now. So we're going to take and use this fetch all function. And we're going to update our location detail screen. So let's import the location class. And we're going to update the following, we're going to update the app bar title, we're going to update this image banner, and then we're going to iterate over every fact of every of the location we're going to load and render a given text section. So how we're going to do that is simple way at first, we're going to load all those locations in the build method. So we're going to say location dot fetch all. And then we're going to assign a given location. So So for a given list locations as a list type, there's a special kind of property called first. And that's just like saying, like this, basically. And right now, we don't have multiple locations. We're going to implement the next lesson. We're just going to assume we just have one location because we're just loading a location detail screen here. In the next lesson, we're going to pass in an identifier to location detail screen and then load it by identifier. Another word before I continue is that usually you don't want to load data in the build function because the build function of any widget can be called multiple times. So we don't want to be doing that. just to get it to work for now, we're going to be doing it here. And I'll explain in later lessons, how the kind of ideal way to do it. So now we have access to our given location. So I can update the title here. And I could say location dot name because location has a name property. As you can see here, this is the name property. And then I can say in the image banner, say location dot image path. That's the another property here. So let's reload that. And it looks like it's working pretty well. So what are we going to do with each text section? So basically, in Dart, there is a special function called map. And what a map does is it converts a list or an array, and Dart is called list, of stuff to another list, but of another type of data. So if I have a list of, let's say, strings, I can use map to convert it to a list of actual objects, like a list of widgets, right? In our case, what we're going to do is we're going to have a list of location facts, which is an array of I'll show you the model, it's going to be this data type list of location facts. And, again, just touching over this again, this is what we call generics. So we've went over this in the last few lessons, but I want to refresh real quick before I continue. it's going to be a list of location facts. So generics is basically the ability to define a given type for specifying the type of something. So you have to specify a list of something you could say, list of string, you could say list of integers. And in our case, we're going to have a list of location facts. So that's what generics is. Anyway, where the map function was, we're going to say, for a given list of location facts, we're going to convert that. to a list of widgets of type text section. So that's what map does, it transforms of one type of list into another type of list. So how are we going to do that, let's make a function where we're going to take all this stuff, we're going to cut it out. And we're going to say some list of widgets. And, and then we're going to just add it in here after the fact. So before we do go ahead and do that, let me implement a function that returns that list of widgets that implements our map function. So what we're going to do is we're going to have a list of widgets, that's the function is going to return. And let me look at the code real quick, what we're going to call it, it was called text sections. So the blog post I just brought up has the kind of final implementation, but I wanted to do it from scratch here. It's going to it's going to take a single location. And that location, We're going to say location.fax. Again, it's a list item. And we're going to say.map. And dot map takes a what's called a anonymous function. In other words, it's another word for it is a closure in Dart. And a closures are something very pervasive through other programming languages. And the syntax is just kind of weird, a closure or an anonymous function is a function, but you don't give it a name. It just it's anonymous, you don't have a name for it. So f is our function. And we're going to implement our function right in here. So the function, because how map works, the function will take one single parameter, and the parameter is, it's a given fact. So anonymous functions in Dart have three parts to it. The first part is the actual list of parameters of the function, just like any other function, this is a list of parameters. And the number of parameters that's available is defined by this actual map here. So we know that if we click into it, this is pretty cryptic, this function that it's defining that we pass in will only allow us to have one kind of parameter. But I wouldn't look at this as pretty complex. Anyways, a list of parameters. And then there is a arrow here, it's called a rocket notation or something, which is saying, hey, we want to define a single line implementation of our function. So In theory, we can do this, we can use curly braces and implement our function here. But what this arrow does is it lets us define if it's the function is a single line, it lets us define the function as a single line of code. So we can say, and whatever we define here as a statement, it returns so we can, if we want to return, let's say foo bar, it'll, we can do it like this, right. So what we want to do is the implementation of this is return a text section. So remember, we had a text section widget here. And that's what we're going to implement. So text section. And then for the fact, we're going to have fact, what is it a fact has a title and text. So fact, title, and fact, text. So this again, as I said, just to go over this one more time, because you're going to be using this lot in Flutter apps is map will convert a list of one type to a list of another type, right. So in here, we're going to, it's going to iterate each fact in the facts list. And for each fact, we're going to execute a single statement as denoted by this. And that statement is going to return what's going to be pushed into the new list. So it's going to return a text section. And we're going to we implement the instantiation of our text section. And then it's going to return it. So this is going to return a iterable kind of list of stuff. So iterable of a given type. So iterable is another thing in Dart that's kind of a kind of like a parent grandfather type of something that you can iterate over. It's something generic, but we're not going to be it's not useful to us. So what we can do is we need to get get a list. So for iterable, we can just say to list and to list will convert something that's iterable to an actual list type here. So yeah, that's it. That's the implementation. We return this. And then we need to use this list of text sessions we return here. So we can't just call text sections like this and pass in location. because we want to add because this is a list, we want to add it to the existing list of it, we want to inject it into our list here. So this is already our list, we want to inject it here. And basically, we're going to do this, we're going to use darts spread operator. And it's called the cascade spread is coming out in the next version of Dart. And, and that's different. But cascade is two dots. And what cascade does is it takes a given item, and it lets you run a function against it or or make an assignment or do something else. So I'm going to say the cascade operator. And then we're just going to say, add all so I'm going to, there's a special function in dark called add all. And what that does is, it depends all objects of something that's iterable to the end of the list. So we have a given list here, we're going to say at all, and then we're going to pass it a something that's iterable. So text sections is iterable. And that's what we're going to do. So there's a lot to unpack there. But this is kind of a common situation. In Dart 2.3, which is coming out very soon, you'll be able to use another operator called the spread operator, which is three dots, and kind of tack on list items like that more easily. So anyway, let's reload this screen. And yeah, there we have the text here. So all the text looks nice here. And that's it. Um, let's see what else we have to cover here. So if you want to go over what cascades are, I have links to what cascades are I have, I have a link to what the map function is. I have notes on it. But I also have a link to the actual documentation in the in the dart website. So this is a link to it. And yeah, like, you know, I would say play around with this stuff. And in summary, basically, I guess that's what we cut. That's all we need to cover. So our app now dynamically adapts to whatever data we've defined. So in the next section, next lesson, we're going to be covering more advanced features, and building out a new screen. So thanks for watching. So in this episode, we're going to be covering navigation in Flutter and also the List View widget, which is a really important widget because most apps are made up of some kind of List View of stuff. It could be news feed items, photos, whatever. And finally, we're going to be covering Gesture Detector also. So we're going to be implementing the second major screen of our app, the Tourism Co app, and you'll be able to... browse through a list of locations, and tap on one to get to this detail screen that we've already implemented here. So let's get started. If you want to follow the code and just get a copy of the code we're going to be implementing in this lesson, you can check out the repo at this blog post on fluttercrashcourse.com. It's called Navigation in Flutter. And there's a link for the code for this lesson up here. And you have to check out the branch step slash step 06. So first thing we want to do is update our fixture data. So fixture data, again, is just test data. But we want to show a lot more locations. So we can show this list view widget easily. We're also going to add a new field to the location model, which is ID. And what ID is going to do is it's a unique identifier that lets us pass around in our app so that we can load a given detail screen. So if I tap on location with ID two, for example, I then make a call to my backend to say, hey, fetch me all the data for location two. So we're not integrating with a backend quite yet, but that's the kind of code we're going to implement before we actually do that integration just to wire things up. So You can check out the branch to just copy and paste this new location data if you want. I'm going to do that right now. So let's open our project. So the we're going to open the location model. And right now we only have one instance of a location. So we're going to want to create three. And before we paste that in, I'm going to actually implement this ID member. So int ID for location, and it's going to be an int. Different apps do use different forms of identifiers. Sometimes they use a string as a GUID. But in our case, we're just going to use an old fashioned just int. So we have to update our controller here, our constructor rather, sorry. And then I'm just going to paste in what I have here to the side. And that'll be a lot easier. So Boom, done. That's it. Let's make sure we have the images in our app. So every location refers to an image. So an image file locally later, we're going to be loading it from a URL. So right now, I don't have all the images. So I'm going to have to take the images from an exit the branch called step slash step 06. And I'm just going to copy it now off screen. So I've checked it out off screen, I'm going to copy it. And then I'm going to now paste it into the assets directory and the images subdirectory there. So I'm going to paste it in and boom, they show up. right here. So make sure you have these images here or else they won't show up. Great. So let's go back to my blog post. So as you know, in every lesson, I follow my blog post. So if you want to see the show notes, you can as I talk, let me increase the size for you. So our fixture date is done. So next thing we want to do is implement a new screen, which is the location listing screen. And this is going to be a stateless widget because it's not going to need to maintain any state. And it's going to also use a scaffold, which is that it's that convenience widget that lets us create a new screen. And we're going to create a list view inside of it. And a list view basically takes in a list of items, whatever that is, it's just a bunch of data. And it will render those items and automatically scroll let you scroll those items. If there's you know, if it overflows the screen. So this is the boilerplate, as you see in front of you for the list, how we would use list view, we would basically fetch all of our locations, and pass it map them. And we've covered map in the last lesson. So if you don't know about that, check it out. And for each location, we're going to display the location's name period. And that's it. And then we're going to return a list for the list view. So let's continue on here, I will just implement it now. And we can build upon this. So we can add an image or make it tapable or whatever. So let's actually implement this. Okay, let's continue here. Um, so open the so the screens directory shows all of our existing screens right now there's there's one folder per screen we already went over. code organization. So this is how we're going to continue to organize our code. So I'm going to hit new folder. And we're going to call it locations, because it's basically a list of locations. And for naming your screens, you want to basically name them as simple as possible. So you don't want to you don't want to name it location listing, it's just too verbose. You can if you want, but it's just too verbose. So I'm going to call it locations and because it's the main screen, I'm going to name it the same name as my directory. And that's really important to be consistent. So let's start implementing this, I'm going to paste in the boilerplate code for a stateless widget, and also our imports. So I need to import app.dart and also the location model. So in terms of the simple screen, pasting that in, we want to use a scaffold. So I'm going to paste that in because we already went over this before, let me increase the text size for you. So and then I'm going to hide the left panel here so you can see it better. So the scaffold takes in a body as you know, and let's go ahead and implement ListView. So I'm going to say ListView. And so there's different versions of ListView you can use right now, we're going to use the traditional ListView constructor, there's some names constructors we're going to use later, but we'll cover that. So if you're used to ListView already, and you're you're implementing it in a different way, just like just follow along and, and just see how I implement ListView. Because the main way to implement it is there is a children parameter. And that children parameter takes the list of a list of whatever you want to render. So it's going to be a list of widgets at the end of the day. And for now, we're going to make it really, really simple. So let's go back to the example in the blog post. Right now, we're going to just implement a list of text widgets. So let me, when I fetch my locations, I'm going to say map and map takes a is basically an anonymous function. So, so for each item in the map, which is a location, I'm going to execute the following function and that function is going to return a widget that represents each item in my list view. So I'm going to return a text widget. And I'm just going to use the location name for the text widget. And then finally, I'm going to convert it back to a list because map returns an iterable type. And that's more of an advanced type that you don't really need to know about right now. But you just have to convert it back to a list because that's what children is. It's a list of widgets. So we have to save that. And let's see, I guess that's it. Let's see if that rendered. So I have my emulator open here. And we have the detail page open now. So now we have to update the app.dart to kind of show this view right here. So let's go to app.dart. And a shortcut for opening things in VS code is Command P or if you're on Windows or Linux, it's Ctrl P. And then you just type the name of the file. So that's really useful. So basically, the home screen is now not going to be location detail that was just there for example sake, it's going to be now location. So let's update our imports. And I'm going to update this, save it. And now let me let me just do this here. Bear with me. That way you can see the code in the screen here. Cool. Now this is a very basic list view. It doesn't look really cool. It just shows like a single name. And that's it. There's nothing fancy about it. We're going to be adding an image for each item here later. So oops, I'm going to show you that. So I have the mockup. of like the actual end result of our app here, and I've showed it to you before. Let me open it for you here in a new window, because it's not letting me show it to you. Let's see location list. Yeah, so this is going to be our final list view, we're going to implement the list view is going to have one image per item. And it's going to have a widget at the bottom with with the name, the opening times of the location, and just some subtitles. So that's what we're going to get to. So we're not going to render those images quite yet, though. So great. Now let's we let's cover how to interact with an actual ListView item. So we're going to implement a gesture detector. And the gesture detector is something very basic and flutter. Most other widgets already include the ability to detect a tap, it could be in the form of a button. or whatever. But a gesture detector is the kind of parent type that's can be used for really any widget. So we can wrap anything with a gesture detector and actually pass on an anonymous method. And that method can do whatever we want. And in this case, we're going to navigate to the location detail screen. So let's implement a gesture detector. So basically, to implement gesture detector, it's it's its own widget. So because it's, it's just a widget here. Let me just do a word wrap here. Right? Right. Great. And I'm going to hide the left bar here. So it's it's another widget. So we can wrap the text widget here with a gesture detector. And a gesture detector has a child which is going to be the actual thing. And And let's see child text there, there, and then and the parentheses here, and save it, it's going to automatically format. And it's not going to do anything yet, because we have to implement a new kind of parameter here. So instead of only providing a child, there's another parameter you're going to provide, which is called on tap. And on tap takes, let's click into it to see how you implement that. an on tap is a type of gesture tap callback. And if you type, tap into gesture tap callback, if you click into it, you're going to see it's just going to be a function, a general function. So you can click into this as much as you want to see how things are implemented. But just trust the process for now that it's it's going to be a actual function anonymous function. And let's implement that now. So Because it's just a generic function, it doesn't take any parameters. So we're going to do the parentheses here because without any list of parameters, and then the arrow here, the rocket notation. And now we're going to implement the function for on tap. And because it's a little bit more complex, we're going to pass it the name of another function so that we're not implementing the function right in here with like a block, it's going to just get too messy. So we're going to implement a function called on location tab. So it's really important to name your functions very explicitly. So we're tapping a specific location. What's not ideal, in my opinion, is to name it something like handle tap or handle location tab. Well, I guess the handle location tabs fine, but on location tab is something a little more concise. And it's already like explicit that it's a handler. So on location tab. I think is the best terminology. And it's important to be good about terminology when you code something because it makes sure that your code is nice and concise. Okay, so let's implement this now. Um, it's gonna we're going to pass in the context. So as you're going to see in a sec, we're going to need to use this context variable. And what we're going to do is pass in the ID of the location, what's important is, we're not going to pass in the actual location, because in Dart, it's going to make a copy of that location instance. And that's not really memory efficient, what we want to do is pass only the absolute minimum data we need to any function we're going to use, because because we don't, again, we don't want to copy actual entire object instances. So we're going to do that. And let's implement that method right now. So because this method doesn't return anything, We can say void on location tab. But what I usually do is I just leave out the void. If it's returning void, you can just omit that. And it passes a build context, and then the location ID. And so what this is going to do is going to navigate to the new screen. So now let's talk about navigation next before we actually implement it. Okay, so before we start any implementation, let's just talk some navigation concepts. So in any mobile app, navigation works like a deck of cards where every card in the deck is a screen. And when your app loads for the first time, it's only going to start off with one card because there's only one screen loaded. And that is defined in app.dart here in the Material App widget by the home parameter. And we already went over this, but that home is the starter screen for your app. So your app just starts, and it starts with one screen and one card in the deck. Now, when I tap on an item in my list view here, which we're going to implement, it's going to load a new screen. It's going to load the location detail screen, which is another card in your virtual deck of cards. and it's going to take that card and move it on top of the other card in your deck into the view for the user so that you're pushing and popping cards at the end of the day. So it's basically in computer science terms a stack and that stack you can push more cards on top of the deck and the card on the very top of the deck is what shows to the user and when you want to go back, so let's say they tap the back button, that card slides off the top of the deck and the previous screen is still there for the user. So the previous screen is still in memory. So when we define a series of screens in our app in Flutter and a lot of other kind of mobile frameworks, you're defining a list of what we call routes. And that borrows from web app development terminology where a route is a basic URL that is a path to a page. So the home page route is just slash. another screen route is like slash whatever. So in Flutter, you're defining routes. And these are called named routes, because for every route, you're giving it a name. So let's define that there's a parameter here in material app called routes. Now, ultimately, we won't be using this parameter, because I'll show you the shortcomings of it. But for very simple applications, it works really well. Because if you don't have any kind of like fancy context you want to pass to your new screen, it works fine. And I'll explain that in a sec. I'll explain what I mean by that in a sec. So let's open up the blog post to show you the example here. And I'm just going to copy and paste this in because it doesn't make sense to type it all out. So in a very, very traditional app, when we have routes, we have the slash as the just we can call it whatever you want, but it's usually using slash. as the home screen, this is the first screen that loads, right. And instead of home, we can say like initial route, and we can just refer to that route by name, because the name of that route is just slash, when we want to navigate to another screen, we have to first defined that route to that screen and that screen is like slash second or like foobar or whatever you want to name it, right. And to navigate to that screen, then I can refer to that screen by name or the route name. So I can say navigator pushed named context, slash and then you know the name of the route. So going back to my detail page, if I tap on a location, I can say navigator, which is a to basically work with navigation and flutter, there's a class called navigator. And you say push names, which is a named route, and you pass it the build context and then the name of the route you defined. Very simple. Now the shortcoming to this is like pretty clear because if your second screen needs to pass any parameters if you need to pass any parameters to it like foobar, whatever, like this, right? Where are you going to get the values to those parameters? That's a shortcoming because there's no way to define how those parameters that data is going to get there if those parameters are dynamic. So for example, if I have the location detail screen here, location detail, and I need to pass the ID of the location we're loading, how am I going to know what ID that is by defining it up here in material route. So there's a solution that we're going to implement. And it's standard flutter, but it's not like documented very clearly. It's it's kind of a little bit more ways into the official documentation. So I don't recommend defining routes like this because they're really it's just that's that's the big shortcoming to that and I hope that makes that explanation makes sense. So let's basically take a pause and implement the location detail screen on how we need to load it because I can't implement a working example of location detail screen unless we update it. Now we went over the fact that the location detail screen right now. only takes it doesn't take any parameters like it just loads any random location, right? This is my location detail screen, it just fetches all locations. And then it says whatever first location you have just loaded. So we're now going to have to quickly update the location detail screen to take in a parameter. So let's go do that now. So we're going to have an int as a private number called location ID. Now remember, this is still a stateless widget because location ID, we don't need this data to react to any kind of state changes, it just loads this location ID when it loads. And that really doesn't change. So let's create a constructor now, a custom one, so that we can load the location ID and make an assignment to the private members. So I can call location detail, pass in the ID. And then we're going to need a way to fetch a specific location. by ID and then loaded here. And we don't have a method for that. So the only methods we have in the location model is just fetch all. So we're going to have to implement a method that closely resembles what we're going to ultimately be implementing, which is a call to our backend service, which fetches a model by ID identifier. So let's go ahead and implement a function called fetch by ID. So we still have the fetch all that that's going to be used still. But I'm going to implement static a static method, because we don't need to instantiate a location. And it's going to return a location fetch by ID. And that's going to be the name of it. And we're going to pass in a location ID. And then what we're going to do is, whenever you implement a function that the easiest way to implement it is just to write out pseudocode. So and then implement that because it's just easier to implement. So we're going to say, fetch all locations. iterate them. And when we find the location with the ID we want, kind of return it immediately, of course is going to get this is a trivial example, we're going to be replacing it with a back end API call. But it's not an efficient way of kind of implementing this, but it gets the job done for now. So we're gonna first fetch all our locations. So we're gonna say location, fetch all and, and then I'm going to have a for loop. And in a for loop in Dart is pretty strict, simple. It looks like a lot for loops to use in other programming languages. So I don't need to explain too much. So we're going to say iterate all the locations, and then locations, I so the location at index i, if the ID matches location ID. return immediately the location at index i. And I know what you're saying, we can probably load all the locations and a map and instantly fetch those locations via a map. But this is just a simpler example. So we're going to have now fetch by ID. Now later, we're going to be going over this is an error because we're not implementing haven't fully implemented our screen yet. In the future, you're going to write an actual test for this. And we'll go over testing later. Like, you're not going to just write functions and then just expect them to work. It's best to have a unit test for that. But that's it for another episode. Also, let's move this method down here, because it's a little bit more of an explicit method. And we want to show all of this data up here just to make it nicer looking. So now let's implement the location detail. And the location detail screen will call this method. So we're going to say location fetch by ID. And then we can pass it simply our location ID and name it a variable location. And then we can remove this. So now we we will this this is working fine, we can instantiate location detail and instantiate it has a location ID automatically. And then when the screen loads, we fetch it by ID great. So now, let's implement. Basically, we can't implement push named as I talked to you about, like, like, we have to pass in an actual ID. So I'm going to now go over how to pass in dynamic arguments to the screen we want to load. Okay, so let's implement what we're actually going to be coding at the final implementation of this. So instead of it, we're not going to use the normal push names, we're going to use a more extended version of push named and we're going to pass in an argument to push names, which is the ID, the location ID here. So let's implement that now. So before we do that, first, I'm going to go to app dot Dart. And this is how I personally implement this. There's many different ways of implementing routes. But I'm going to have two constants at the top of app because constants allow me to define, like refer to location route globally by the actual name without having to. It just prevents mistakes. So I can refer to the location name by an actual variable name. And in constants in Dart, should be starting with a capital letter. So this is going to be in title case, these aren't classes, they're actual variables. So they look like classes, but they're actual variables. But again, they're in title case, because they're constant. So I define all the names of my routes up here, I have the home route, which is just slash, and the location detail route. Now when you pass the slash route to flutter, it's already going to know, hey, this is my first screen, I'm going to load. Great. So now let's go back. And now I can say push named and then locations route. And then I'm going to show you how I can pass an argument to that. So we're gonna have to pass this location ID to this push named function. And to pass an argument to it, there's an arguments parameter. So for push names, we have arguments. And all that arguments is a map. So a map type, and then we can define whatever we want here, I can say ID. and then location ID. And our screen is actually going to use this and I'll show you in a minute how it's going to use it. So we're going to refer to it by name like ID and then the value location ID. And we're going to remember that we use this ID key to our map. So let's continue on. So in app dot Dart, here's what we're going to do, we're not going to use the routes parameter here. So I'm going to remove that. Also, we don't really need initial route because we already have a route called slash and that just loads first, we're going to have we're going to use a special parameter called on generate route. And on generate route is giving us a dynamic list of routes. It's in the form of what's called a route factory. And route factory is just a fancy term, which is a basically a payload that of data. So chunk of data that just says, Hey, here are my routes. So let's create a pass it a function we're going to implement. It's a private function. So starting with underscore called routes. And now we're going to implement that here because it's in our app dot dart, it's on the highest level, it's easiest to define that here. So it's going to return a route factory. And I'll show you what a route factory is at the end of the day, in a second rather. And this function is going to return some data. So it's going to return an actual function. So if you click into on generate route, that is a route factory. Let's click in a route factory. And route factory is actually a function that takes in a bunch of settings and returns a route of type dynamic. So I won't like drill into this too much, let me implement that. And that will make a lot more sense. But what we have to do at the end of the day is return a function. So a function with the parameter settings. So we're going to use settings here. And I'll show you how we're going to use settings. So first, we're going to get the arguments to our whatever route was tapped. So arguments, and settings has this member called arguments. So We can use the settings for getting all kinds of information, but arguments is one of them. And now we're going to create a variable called screen and screen is the actual widget and the final screen that's going to be returned to us based on the name of the route. So the name of the route that we have is defined as settings dot name. So if a user taps on whatever they tap on, the given route that they're wanting to reach, is defined by the name, which is going to be either slash or slash location detail. And what we're going to do is use a new feature of dark called switch and switch. Let's it's basically a glorified if and then else if statement and it has can have as many else ifs as you want, but it's just a more concise way of saying if something and then else if something and then else if something else, right. So instead of doing that, we can say switch, and we pass it the name of the route. And then I can say in this case, if it's the locations route, I'm going to do something custom, I'm going to say my screen that I want to return. is basically a new instance of the locations widget. And then I'm going to say break because in a switch statement, it will go through every case until it breaks or you return something. So next case is the location detail routes. And remember, every case has to be ended by a colon, not a semicolon. That's really important. And most programming languages have a switch statement. So Most of you if you're familiar with this, it this is going to look like second nature to you. So for the location detail route, if I want to navigate to location detail route here, and that's defined by slash location detail, I have to do something custom now. And I'm going to say location detail. And I'm going to use my arguments map here. And I'm going to refer to it by the ID key. And that's what we defined here. So locations, the arguments is a map. And there's a key in that map called ID, you should use single quotes, by the way, by default. And then, and now I can instantiate with a custom argument. So now I have my screen, I have to import it real quick. Location, detail, location, detail, great. And now I can return it. So break and now the switch statement has this final case, which is if none of the cases match, there's this default case, and you define it with just default colon. And then by default, just running going to return null and do nothing. And then finally, what I'm going to do is return what's called a material page routes. And we know that we need to return this because a route factory is a function. And yeah, I won't get into it too much right now. But let me just say that you it expects a material page route to be returned, right. And material page route is a type of is basically a type of route. So going back to the basically the route factory type, a material page route, basically, I didn't want to get too much into it. But it is a type of route. So you can use any type of route, there's multiple types of route, but the most popular is a material page route. And then material page route takes in a builder. And I wouldn't worry about builder, all it is is a fancy fancy way of being able to pass in something dynamic, like an anonymous function here. So the syntax is a little weird, but basically, it's a function that takes in a context and you say, Okay, what what am I returning, I'm returning my screen widget. And that's it. So I know this looks a little weird. But basically, this is how we define all like, all the routes in our app that need to be dynamic. And what's nice about it is that it's defined upfront in our app widget. So let's get this working. And then I'll show you how it's going to work now. So on generate route is routes. And before we get it working, I'm going to quickly clean this up real quick, because I want to use the I'm basically going to take my theme data before this before we get it to work real quick. Let me just tidy this up because it looks pretty, pretty, pretty ugly. Let me say theme data. Sorry for the tangent here. But I want to just put this here. And I'll show you how easy it is to quickly get this tidied up. Great. So our main screen is very clear on our app widget, we have just on generate route and our theme, and it's in a method here so that it's nice and clean. Cool. So now that we've gone over that it was a little tedious, but let's see if this will work. So let's check our code again, push named, okay, this should work. Let's see if this works. Cool. Now, it's not loading the location detail screen and see it's just like loading the location screen. So let's troubleshoot why this is happening. So in our app dot dart, location to those location details, the location detail route and The name we're loading is see, location detail route. So we have to push named location detail routes. And let's hot reload this. And when I click on something cool, it comes up. So we got it working, I can go back. And when I go back, it will pop it off the route. So there's no, you don't need to implement this pop method, like you don't need to manually write some code that says, push this. card that's on top of our deck off the stack, it'll just do it automatically, because we're using the material apps, material designs app bar widget. So app bar widget automatically will show a back button when the screen appears if it's not the home route. So cool. So in our next episode, we're going to actually implement the the beautiful location listing screen. But this is just the nitty gritty. kind of mechanism for navigation. Let me make sure I didn't miss anything, because the blog post basically explains in detail how this is all implemented. And it gives you also links to the documentation. Let's see. Yeah, I guess that's it. Final app dot Dart file. Cool. And I talked about going back and all that stuff like that. So there might be a better way that you have for implementing routes that are dynamic that need dynamic parameters. But you know, feel free to reach out if you have a better way of doing this. But for now, and how flutter is implemented, this is pretty much the most clear cut way of doing that. Everything's defined up front in app dot dark. So thanks for watching. And yeah,