Building a Windows Desktop App in Flutter - MetaTube

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video I'll be showing you how to make a desktop application using flutter we'll be making the app I made metatube which makes handling YouTube video metadata much easier now I know some of you won't need to use this app unless you're making YouTube videos but I still encourage you to watch the video as it will teach you a lot of useful information that you will use in your desktop applications in this video you'll learn proper folder structure how to set up your apps window reading and writing data making custom widgets and services and most importantly turning your app into an exe that you can stall on your computer we've got a lot to do so let's get started to get started we're going to launch our Command Prompt CD into our desktop and then do flutter create and then the app name which is meta tube we're gonna wait for that to build then we're going to CD into meta tube and then run code.to open it up in vs code now that we have that opened we can go over to our lib folder open up our main dot Dart file and hit F5 we now have our app launched and we can go ahead and resize it bring it over here and then we can get started with our Windows app so first we want to hit Ctrl shift n and select everything and delete it and then we're going to create our own stateless widget called my app instead of returning a placeholder we're going to return a material app and then we're going to give this a turn off the banner at the top right with false boss and then we'll go ahead and set up our home and then our home is going to be home screen and we need to make this so we can save this create a new file by going into our lib folder and make a new folder called screens and then inside that we'll make a new file called home under screen underscore screen dot Dart I actually changed my shortcut so that I can make new folders and files a little bit easier but you can just right click and make a folder or change your shortcuts as well we're going to import our material app there we go and then we're going to create a stateful widget this time and this is going to be home screen we need stateful widgets because we're going to be using States so it's very important that we have a stateful widget we can go back to our mean.dart file and then control period to import our new screen and there we go we now have a blank screen and we can get started so we can close our main.dart file we don't need it right now we'll come back to it later and we can start styling up our home screen so first we're going to return a scaffold inside of our scaffold we're going to give it a background color now for our colors there's a lot of different ways that we could do this we could use a theme which is probably the better way especially if you're going to switch between a light and dark theme but we're going to be making a custom file just to handle all of our colors so we can go into our lib folder make a new folder and this will be called utils and then inside this folder we'll make a new file called app underscore Styles dot Dart we're going to import our material again because everything needs it and then we can go ahead and create a class this time and then this class is going to be called app Theme and then we're going to put in all of our colors in our app theme for our background color we can make a static const and then this will allow us to make a color and then this color is just going to be called Dark we're going to be using this color a lot so instead of naming it just our background color we're just going to make a color that we'll use all the time if we need it as a dark color whatever way you want to do it is fine you could do individuals if you want or if it's reusable just make it easier and rename it something that you can use over and over and then for this our color is going to be a hex color which is 0x FF which means there's no transparency and then the color is one e one e one e which is a nice black background which is the same color as my wallpaper we can go back to our home screen and now we can call our new app Theme right here it's going to Auto Import and we have app Theme dot dark great and then if we save we're going to have a nice black background just like what we want and then delete the const I also set it up where it on save it auto formats also adds any cons and all of that stuff so that's why that's happening yours might not do that but you can definitely set that up let me know in the comments below if you need help setting that up and I'll help you out so now what we need to do is we need to add in a body and our body is going to be a column because that's all we really need and we're going to just put everything in our column so we're going to give our columns some children so for our column we're actually going to separate this into essentially two different sections so maybe three depending what we want to do but the mean section is going to be a row and this is going to be our icons at the top and then we can call our children so because we're going to be using buttons at the top we're actually going to be reusing our button so instead of just hard coding them in right here what we're going to do is we're going to create a method that allows us to reuse it as many times that we want to make a button so we can do this by coming down right before the last bracket and then we can create a method our first method is going to be an elevated button so we can call elevated button which means it returns an elevated button and then we're going to call it mean button we'll be using this for our new file button at the top as well as our save file button at the bottom and then we can go ahead and actually return an elevated button now an elevated button is actually going to take two parameters which are right here on pressed and child we're actually going to make the child a text and then we're going to return this section right here so what we can do is if you don't know what you're looking to return you can actually highlight over what it is and right here the on pressed is actually a function that could also be null which is why it has a question mark so we can actually add that right here and we can pass that when we call the main button that way we can make individual ones have different or impressed events as well as different texts so to do that we can just say it's a function question mark which means it could be null and we'll just call it on pressed and then for our second one we know that text is a date is a string so we'll use string and then we can just call it text and then we can go ahead and replace the data with text and now we actually have a button if we call it we can come up here and call it get rid of the const and we can go ahead and do main button and now our mean button is looking for a function as well as a string and in the string we can do new file and save it and there we go we now have a button that we made but the best part is we could actually uh and we're going to later but we could copy this button and make it our save file and now we have a new file and a save file and all we had to do is pass in different parameters now we don't want our save file at the top we just want our new file and then what we're going to do is we're going to be adding two more buttons on the right so we can do that and group them together by making another row anytime you're in a row and you want stuff to be separated and you just make another row and group those together so just like our main button what we're going to want to do is add another buttons for our icons and we can do that by coming back down below the elevated button and then this one is going to be an icon button and this icon button is going to be called action button because that's our actions you can name it whatever you want but that's what I chose to do and then we're going to return an icon button perfect and just like before the icon button is going to take on an on-pressed which again we already know is a function question mark so we can do that now function question mark again that means that it could be null we can pass null if we want to and then it's going to take in an icon now it's not looking for an icon I mean in theory you could pass an icon but it's going to be easier if we just pass an actual icon rather than the icon I know that doesn't make sense but what I'm trying to say is we can make an icon first and then our icon will actually need an icon and then we can do icon data and then call it icon and what this does is allows us to actually just specify what icon we want rather than having to create the icon with what icon we want and we can do it that way and then we do want to add a color to this icon we'll actually call it first and I'll show you why so if we call the action button it's going to pass in our null function at the moment and then we can pass in an icon by doing icons Dot and then the first one is file upload and then we're gonna get issues with the const again that's my fault not yours and there we go and now we can see that the icon is black which is not what we want but we can actually now duplicate this and then just change the fold uh to a folder for the second one and now we have both of our icons and if we click them there's a few issues with it which is what we want to change obviously the color but also the splash so we can work on the color first come into the icon and now we can actually pass in a color well we don't have a color made so we want to go to our app Styles and make another color static const color this one will be called medium because it's in between our dark and what we'll be using as light and this is going to be 0x and then this one is going to have some opacity which we're going to use 50 and then it's pure white with opacity of 50 which is F's great now we can call in our app Theme dot medium this time and now our icons are the color that we want they still have a few issues though the first issue is going to be the splash so we can change it to Splash radius so we want the splash radius to be 20. now the slash is much smaller towards the icon and then we also want to add a splash color which is going to be our accent color which we don't have made yet either so we can go back into our static const color and then we can do accents which is going to be a nice orange so this is 0xff and then it's FFA 500 and then this is going to be our orange color and then we can go ahead and give it right here to our Splash radius this is app Theme dot accent and now when we click it it's a nice orange color now these look a little too close together they kind of overlap a tiny bit which I don't really want so I can go ahead and just add a size box in between with a width of eight I like to work on an eight grid you know that from my previous videos most people do so we're just going to make it eight we could do four if we want to but we'll do eight which is fine I want it to not be an accident that I click on it which if they're closer I could possibly do that great and then with our functions we can go ahead and actually add in a um we want to space these apart so we can do this by doing on our first row we want to do main axis alignment and then space between and then this will push them completely apart and this is why we put these two in another row because now it's like a row here and a button here and that's why there's a gap if you didn't do the other row these would just be in the middle in a second and stuff like that so cool now obviously this is too close to the edges so we can come up to our column hit control period and add in a wrap with a padding and then we can change the padding to symmetric and then the symmetric that we're going to do is a horizontal we'll do 40 and then vertical vertical we'll do 20. and this will push it 20 from the top and bottom and then 40 from the left and right great now what we can do is put a comma here and then that's pretty much it for our top section these don't do anything yet and we'll make them do stuff later but actually our button is not how we want our button so what we want to do is we want to create a style on our button because I don't want it to be blue you could make it blue if you want to but I want mine to be orange so what we can do is we can come down here below the icon button and then we can actually make a button style and to do this we can do button Style and then we can do underscore button style the underscores mean it's private which means only this file is going to access it and it's very good practice to make everything private unless it needs to be accessed somewhere else then you can make it public by removing the underscore um that's what the underscore means in case you're running and then here we're going to return a style now we don't want to recreate an entire style ourselves so what we can do is we can actually already grab the elevated button Style by calling elevated button dot style from and this is going to grab the exact style that the button has but then what we can do is we can go ahead and add in a differences that we want it to be so first we want a background color to be different and we can do this by calling app Theme dot accent and then when we save this we actually need to apply this to my elevated button so we can do that by calling style and then do underscore button style perfect and now my button is the orange color that I want but I also want to change a little bit so we can do a foreground color this is going to be the text inside of our button and we just want this to be at theme.dark great now sometimes our button can be disabled and we're actually going to do that later with our saved button and if we test this let's come back up here if we were to pass null as the actual function rather than a function that returns null our button is now disabled and I don't like this approach because you can't really see what that is so what we're going to do is we're going to change it just a little bit and we can do that by adding it to our style so we now have the ability to make a disabled background color but because we're using a color we want to go back to our app Styles and create that so we can do static const color and then this one will be disabled background color and then we can just call it colors because we're going to use a built ink color rather than make our own and it'll be black 12. now we can come back here and then just call that app Theme disabled background color and when we save that now it's a little bit different and then we also want to change the disabled foreground color so we'll go back to our app Styles and then make another one static cons color disabled foreground color equals colors dot white 12 and the 12 just means there's some transparency you can see this by hovering over it the transparency is right here it's 12. perfect and then we can go back and then call this one as well disabled foreground color and now it's a little bit different it's still disabled but at least this way you can read it and then of course in our design later it will say show save file um but there that way hey why can't I hit save file oh well I have to fill out all the inputs and then you'll be able to but that's how we're going to handle that which is nice cool so now we've created our buttons and we've also gone ahead and made styles for them now what we can do is we can start working on the next section which is going to be our inputs our text Fields so we want to come below the row right here's the row and then we can actually add in a little bit of space here as well so we can do a sized box with a height of 20. that way there's a little bit spacing between the Botta the top and the bottom and then what we want to do is instead of using a text field which we could do just by doing text field we're going to reuse this text field a lot so instead of calling it right here what we want to do is we want to create a custom widget that we'll be using in our design over and over we could actually make it a method but I don't like to make too many methods especially if it's something you could use elsewhere in the app it's better if you're only going to be using methods is if it's in the actual file itself if it's going to be somewhere else or could be somewhere else we want to Branch it out into a different file just to make it cleaner especially our text field is going to be pretty big so I don't want to again I like to have at least amount of stuff in my files as possible just to make it easier to maintain for my purse no preference but you could make it a method in here but we're going to print it out so to do that we can go to our lib folder we can make a new folder actually we already have yeah we'll make a new folder called widgets and then inside that folder we'll make a new file and this will be just called custom underscore text field dot Dart and then we can go ahead and import our material and then what we want to do is we want to create a stateful widget here as well with our custom text field and the reason why is because it's going to use something that uses state so we want to make sure it's a state and then we can just call this you can call it whatever you want but we're just going to call it custom text field it's the only time that I use this and it is custom so it works fine but we can go ahead and pass that in so to make sure that we're using this we can go back to our home screen and delete out the text field and instead we want to pass in our custom text field we can do that just by calling it and then hit save great now that's a placeholder because we're actually passing in a placeholder but now we can see what it's going to look like when we start customizing it so with our stateful widget we're going to pass in a few variables or properties that we're going to be using this way we can reuse it which is really the whole point of making breakout stuff is so that it can be reusable it's going to have different information so we need to pass that in here and we can do that by calling final and then what the type of information it is in this case it's going to be an mint and our first one is going to be max length this is the max amount of characters that we can use in our input fields which we'll show later the next one is going to be final ins but then this one could also be null we don't make it null and it's our Max lines but you could make it null in case you don't want to have a Max lines I specify all of my lines just for the design but again adding a question mark means that you could pass it as null and then it won't be that so that's what the question mark means that took me a while to figure out and we'll be using those a lot so I'll try to mention them again but question mark after the variable after the the type of information means that it could be null and that's how that's handled next we want to do is a final string and this final string is going to be a hidden text hint text and then we also want to pass in a text editing controller this is very important this is how we'll be able to manage the data in our our input with the controller then we're going to get an error on the actual const here and we can just uh click it and then do odd final and then this will do all of this for us which is really nice saves us a lot of time great and then if we were to go back to our home screen now we're going to get an error on our section because it's looking for this information so we can come up here right below our state screen we can go ahead here and actually add in our text editing controllers and we can do that by doing text editing controller and then we're going to name it now we're going to be deleting these and using a different one but I want this to be able to work so you can see what we're doing so we're going to just call this title controller for now and then it equals a text editing controller perfect we're only going to use one and again we're going to be replacing this so we can do that later so I'll do the custom text field again and now when we call this it's actually looking for all of this information and now we can actually pass it in again with our max length we can do do 100 since it's the title and then for our hint text we're going to do enter video title and then for the controller we're just going to pass in our title controller now when we call this it actually should show up perfect and then we can come back here and save and it's still going to be a placeholder but now we're not getting any errors and as you saw the max lines could be null and it didn't ask me to actually fill out the max lines because again you don't have to if it can be null but we do want to fill out the max lines for our title and this is going to be three but this is why we can actually make all of these null and then that way we don't have to pass them but in this scenario we do want to pass them but that's why we made the max line three in case we don't want to pass it and just let the lines be as long as you want but yeah that's kind of how that works which is cool great and then now what we can do here is we need to go back into our custom text field and we need to start styling it of how we want it so the first thing we're going to add here is we're going to actually add a focus node and a focus node it essentially just means that if you hit tab it'll let you go to the next uh input without having to click all of them so we're going to call this an underscore Focus node because it's private just to this variable but because we have a focus node there's some things when you create stuff you want to actually dispose of them which is why we have the stateful widget and we can do that by calling dispose and dispose essentially just means hey you're going to be here forever until you're not needed and when you're not needed I need you to get out of here so you don't use up resources that's kind of the easiest way for me to explain it it's probably a little more complicated than that but that's kind of how I understand it so there are some things that we want to get rid of focus node is one or text setting controller is another one if we're not using it's kind of waiting for that information in the background and we just want to get rid of it so how we do that is we just make it dispose and then when it's not being used we dispose of it we throw it away and then we recreate it when we need to which is really cool um so make sure you do this you don't necessarily have to add this but definitely make sure that you do so with this now we can actually start doing our input controller or text field so we can do a text field and then we can save this and now everything should update it's still a placeholder custom text field placeholder all right let's go ahead and refresh just to make sure it's grabbing it there we go sometimes you need to refresh if you're changing a lot of things great so now we actually have a text field but we do not want this text field to look like this we want it to look much much better so we can start styling that stuff so we can get rid of the cons because we're going to have to later first we can pass in our Focus node our Focus node is going to be our Focus node very simple there and then because we want to have a focus node we want to use our Focus node and we can do that by on editing complete and then it'll take a function and then this function is focus a scope and then focuscope dot of oops focuscope dot of context there we go and then we just want to grab the next focus and then the next focus is essentially going to be anything that has focus on it I I believe it's just going to skip to the next one which allows us to hit tab now what we want to do is we want to pass in our controller very important that we do this and because the controllers here in our file it's up here before we actually do our state we just need to call widget which is grabbing the widget information and now we can call in our controller we also want to call in our max length so our max length again widget.max length this is why it's very easy to name stuff because it's just the same thing and then of course our last one is going to be Max lines and then widget oops I can't type today widget dot Max lines there we go and then if we save this now we actually have all of the information that we wanted it's very hard to see but right here there's a little 0 out of 100 we have the three lines here which again hard to see which is why we're customizing it but there's three lines here one two three and then any more lines would just scroll so that's kind of what we've added there and then what we can do and then we also have the controller which allows us to grab this information which we'll see so now that we have that out of the way let's start customizing it to how we want it to look so first what we want to do is we want to make sure that it knows that it's keyboard type multi-line we can do this by keyboard type and then text input multi-line I think by default it doesn't tell me what the default is it doesn't tell me what the default is it could actually be null so we'll make it multi-line just to make sure and then we also want to do a cursor color we already have a color for this it's our app Theme dot accent and make sure we import it and then we can call in our accent now that's going to turn this to Orange which is great next what we want to do is we want to add a style and this style is going to be for the text inside so we can go to our app Styles and then we can come down here and make a new style this one is going to be static const text Style and then we'll call this input Style I love how uh vs code is like hey do you want this maybe and then we can call a text Style and then for this textile we're not going to customize it too much uh we're essentially just going to pass in our text color and then we don't have a color for this one so we're going to make it right up here we'll do static const color and then this is going to be our lights and our light is essentially just a hundred percent White so 100 opacity and or not opacity and then appear white and then we can call that here light great and then we also want a font size and our font size is just going to be 20. now when we type uh it doesn't save it because we have to call it so we can do app Theme dot input style and now when we type it's actually Pure White and again you can make this any color but I thought the white looked the best great next what we want to do is we want to get rid of these borders and stuff actually we'll decorate it first so we'll do decoration and then we'll do an input decoration and then this input decoration is going to pass in a few different things the first thing is going to be our hint style and our hint style we need to make as well so we can come back in here now with our hint style uh same as before static cons text Style and then we'll do hint style and then it's going to equal a textile now we don't actually have to pass any font size here unless we want it to be different because it's going to grab the input style font size because it happens first so we don't actually have to pass in a different font size if I want it to be the same which is really nice we do however have to pass in our color and for our color we're just going to call medium and that's it and then this way it's white and then when we show in our hint style which we'll get to in a moment you'll see that it's a different color so we need to call that hint style great and then we want to pass in our hint text so our hint text we actually already have so it's widget.hind text and that comes in from the top and then make sure we delete the const great so this is a medium and then this is oops this is medium and then this is white but as you can see if I delete it and paste it in it's the exact same size because it grabs from the input which is nice saves you a step next what we're going to do is we're going to do a focus border Focus border is this blue that I don't like and we're going to switch this to an outline input border and then we're going to pass in a border side which lets us know what's the side it is and it's just going to be all of them so then we're just going to call Border Side and then here we're going to pass in a color and then that color is our accent color and as you can see here we've added a border around our text field but only when it's focused so if we unfocus it it doesn't highlight it great and then what we want to do here is we wanted to do the enabled border so we can come down out of this one we want to do enabled border and then this enabled border is going to be an outline input border just like before Border Side just like before and then we're going to pass in a border side and then this one is going to take a color but the color is going to be our medium color this way it's orange when we're selecting it so when it's in focus and then it's not and as you can see we got rid of that little blue thing because we overwrote it but uh it's gray when it's not selected and then orange when it is selected typing not typing typing not typing so that's kind of the approach I took but you can make this styled exactly how you want and then of course we need to style our little counter at the bottom so you can come out of that one and then do counter style and then this one is very easy it's just going to be app Theme dot counter style but we don't have a counter style so let's go ahead and make one and then this one is similar to the other ones but we'll do static cons text Style there we go and then this one will be counter style equals a text Style and then this is going to be a color of medium and then the font size just a little bit smaller we'll do 14. perfect and then we can go ahead and call it here at theme dot counter Style great and there we go it matches the Border it stays on uh gray though and then if we type it starts counting up until we're at 100 and then once we're at a hundred um it just doesn't let us type anymore great perfect and then lastly we want to have the ability to copy uh paste which I actually have in the design right here and we can add that anywhere we want but we'll put it right above the decoration we can do this by doing a suffix icon oh it has to be in the decoration so we'll put it right below the input decoration we'll do right below the hint text we'll call it suffix icon and the suffix icon we're actually going to make a let's bring it out here we're going to make we're going to Branch it out because it's kind of a lot of information so we can actually break it out just so it's easier to follow so we can come down right below right below the last bracket and then we can do icon button because it's going to be an icon button just like we had before we're going to call it copy button and then this copy button is going to return our copy paste button essentially so we want to bring in our contacts and I'll show you why in a moment but we can do build contacts contacts which is going to pass in the context of our widget build we're actually going to be creating a snack bar when we click this so we need to pass in the context here to pass in the contacts later so that we can use the actual information cool and then we're going to return an icon button Excel and the icon button is going to take an onpressed as well as an icon just like before this is the only time we use it so we don't need to break it out so it's reusable and make it more Dynamic where we could pass in different icons you could definitely do that if you want to but you don't have to so we're just going to pass in an empty uh function for right now and then we're going to add the icon so the icon is going to be icon and then the icon itself is going to be icons dot content copyrounded which is a nice little copy paste there cool now what we want to do is we want to call this so we can see it so we can go right below right above the focus border and call suffix icon and then the suffix icon is going to be our copy button and we're going to pass in the context so now we have it it looks blue just like the other one because that's its default coloring so we want to switch this up a little bit we can do that by adding a color to our icon our color is going to be of course our app Theme accents perfect and then we also want to actually we don't want to pass it the cool thing is with an icon button and I did it earlier with the icon itself but you actually have the ability to pass in a color and then the color we can actually just do this app uh app Theme accent so before I did it on the actual icon itself but technically I could just done it here so again different ways to do different things and of course when we click this button we do have the same issues as before so the splash radius is going to be 20. we need to change it here Splash radius 20. there we go and then we're gonna just keep it this color um now we'll switch it out then so we'll do Splash radio Splash color and then the same as before so app Theme accent and then just like we had before it works the same way as these do cool uh now the cool thing though is we can also add a disabled color which is why we did it as colored so we have a color and then a disabled color and then the disabled color is actually going to be our medium so it matches the rest of the Border great but it's not disabled at the moment and we can disable this by passing in our on-pressed as null and now it's disabled but we want to actually handle this a different way instead of passing in a hard-coded variable we actually want to make it where if this is empty then it's disabled but the moment has text in it that we can copy then we want to actually paste that in so what we can do is we can actually check that by going widget dot controller because we have access to the controller dot the text inside of the controller and is not empty so what we're saying here is is the widget controller it's text not empty and if it is then we can pass in a function that means that it's not empty which means there's text in there so right now we're going to pass in an empty a variable but it'll let us click it and then if it is empty well we don't want to do anything so we can disable it alright so for this to work we're actually going to have to pass in the function because right now this is still returning null which is why it's still disabled so let's go ahead and add in our function that we want and we can do that by coming up here above our build context and we can actually start creating our function that is going to allow us to copy paste the function is going to return a void and then this is going to be copy to clipboard and then we're going to receive the contacts that we've gotten from earlier and then we're also going to pass in a string here that we're going to be able to use as our text for our snack bar so we're going to have to pass in the contacts this is what I said earlier we're going to have to pass in our contacts to our copy button because we're going to have to pass it to our copy the clipboard method as well but then we also have our string and then we can pass in a text and then this way we can use it this way too which is really cool so what we can do here then is we're going to do a clipboard dot set oops we have to import our clipboard so clipboard.sat data and then this data is going to take our clipboard data and then it's going to take in our text as our text so essentially this is just a clipboard.set data grab a set clipboard data it's going to require some text and that text is going to be the text that we're going to pass in Here and Now what we can do here is we can to call this here then and this is why we're getting an issue earlier because it was actually looking for us to return something rather than returning null return null null it's always going to be null so what we can do here then is we can call our function and it is copy to clipboard and then it's going to take in our context and then it's going to take in our text and the text that we want to take in is whatever is in our widget controller widget controller dot text and I'll Loop that then so what this is saying is copy the clipboard grab in the contacts that I've given you and then grab in the data from the widget controller.txt and now when we type in all right so it kind of works at the moment if we have data in it and save our file it does change orange and we can click it but then if we don't and we save our file then it goes gray we're going to come back and fix this I think it's just based on how we have it set up it's not working properly but we'll come back to fix this because it'll work in the end but let's go back to our copy to clipboard and then right below our set data we actually want to pass in a snack bar that we can use to actually give back data to our user that hey you've actually copied this because if we click it I don't know what that did so we can create a snack bar now the snack bar we're actually going to be using all over our app so what we can do is we can actually turn it into a utility by coming over to our utils make a new file and call the snack bar underscore utils dot Dart and then this is very simple we can go ahead and import our material because we're going to use that and then we can actually create a class here and we'll call this class class snack bar utils just so we know which one we're calling and then we're going to pass in a method here as well so we'll do static void and then show the snack bar and then this snack bar is going to take in a few things that we're going to need the first one is going to be the build context like I said earlier we need to pass in the contacts that's going to take it here we also want an icon because we're going to be using an icon if it's good or bad a good error or a bad error so we can do icon data dot icon and then we also want to pass in our message which is going to be a string so we can do string message and then here all we want to do is we want to currently hide the scaffold uh that's already there if there is one there so we can do this by doing scaffold messenger dot of context and then we can do hide current hide current snack bar we always want to do this first otherwise they'll just stack on top of them and if you keep pressing the same buttons over and over it'll just continue on forever and ever so always hide the first one and then what we want to do is we want to show a new one so we can do that by scaffoldmessenger dot of context just like before and then this one is going to show a snack bar and then the snack bar takes in a few things of course it's going to take in a snack bar itself and then the snack bar needs some content so for this content it's very straightforward we're just going to create a row this row is going to have some children and then the first child is going to be an icon and then this icon is going to take in our icon that we're passing in and then we're going to just give it a color of our app Theme dot accent which installs our app Theme there we go and then after our icon we also just want to add in a little bit of width so we'll do a size box width of eight and then we're going to pass in our message and we could style this message as well but I'm okay with the default styling so we can just pass in our message and now what this is essentially doing is just say hey show a snack bar snack bar should have a row inside that row it should have an icon some spacing between the icon and then the message and now we can go back save that and we can go back and we can actually call our snack bar in our custom field when we copy it to do this it's very straightforward we just need to call our new uh snack bar utils Auto Import we're going to call the method that we added which is show snack bar we're going to pass in our contacts that we're getting from our copy to clipboard which we're getting from our copy button which we're getting from our build context because we passed it along all of them we're going to want an icon for this one which is just going to be icons contents copy and then we want to add in a message and this message can just be copy text and there we go so now when we click this when we have the data in which again we're going to fix this it's messing up because of how we're doing our text field like I said earlier our text field is a text editing controller this is just default right now so it's causing some errors we'll fix that later but when we save it it actually grabs that data right away and now we can actually copy this and we'll get our copied text and if we delete our text out we can now paste in the text that it copied this is copied and then we can copy it and then paste it and as you can see it's that simple to add a snack bar as well as copy our text so let's save out of this and close out of it we don't need that anymore and then we can come back to our custom text field and our custom text field is actually done like I said still getting an error this is supposed to change when we type but it's because of how we're temporarily doing our text editing controller which we'll fix later then great now we can go back to our home screen we're done with our custom text field this is what it looks like we can close out of that we can go back to our home screen and we can add in our different text Fields now so we have our one we want to add some spacing in between our height is going to be 40. like so and then we can go ahead and copy this one and we can just rename it to something different now we have all three so we want our second one to have 5 000 uh characters we want it to have uh five Max lengths and then we want to do enter uh video description great and then we want to make a different text editing controller for these so we'll do description uh description controller and then we'll do tags controller and again we're going to replace these which is why they're calling errors um but we'll use these for now just to show you how it works and then we can do tags controller and then video tags and then this one I guess we could do four and five hundred I think is the route we go uh let's copy the spacing here so we actually do 5006 and then 504 and then we do uh 103 great and then we're gonna get an error so we just need to drag this down a little bit uh we'll fix this window layout later we'll do that last there we go now that we have our text setting controllers done and we do want to finish this up with just our save file button at the bottom that is quite easy to do we actually already have it so we're just going to do size box of a height of 20 and then we can go ahead and add in a row just in case we want to add other stuff down here I don't think we do but we could we're going to pass in our children and then we're just gonna pass in our mean button just like before we're gonna pass in null and then the button this is why we make methods because it was very easy to make that save button just like that perfect uh we don't want to save button we won't save file but there we go we now have a new file save file file these two buttons are inputs which at the moment they're not working properly but they do work properly if we save it then we can copy the text so great now what we want to do here is we want to make this so it's a little bit we want this button to be disabled if these are empty so we could do that now actually we're going to wait because we're going to actually create our file service first so that we can actually start getting all of these buttons to work and our actual copy paste thing to work as well so this is kind of where everything comes together and our design actually starts working so we can do that by going over to our lib folder and we're going to make a Services folder and then we're going to make a new file called file underscore service dot Dart we're going to import our material because we're going to need this and then this is where everything kind of gets uh I won't say complicated but we're going to be doing a lot in this file which is why it's a service and we're going to get started by doing class file service and then we're going to return make a bracket great so the first thing what we're going to do is we're going to type in all of our controllers so we're actually going to use the controllers here rather than in our home file we're going to put them in our file service because we're going to need to reference them from our file service we never really need to reference them in our main home screen we just need to call them so we're going to put them here but that is going to give us an arrow on our controllers so what we want to do in order to use our file service is we need to like actually bring it in and we can do this by calling file service which is our new file that we created file with a lowercase service and then it's going to equal our file service so essentially we're just saying hey when we reference file service here it's actually our file service here great and now we can come down here and just call these and we'll do that by doing file service dot title controller file service description controller and file service tags controller great and now we can go ahead and get that working now before we go back to our file service we want to handle our text editing controller so that way we're taking care of them first we want to make sure that they're completely empty before we can hit the C uh not empty before we can hit the save button so we can start adding that function out here so first what we want to do is we want to do an init state which again is why we have the state full widget and then we're going to pass in uh we can delete this out we're going to call a new function and this function is going to add some listeners to our text editing controller so it's going to be void add listeners there we go and then in here we're going to create a list this list is going to be a list of text editing controller and then it's going to be called controllers and inside will give it a list so the list that we can do is we can just hard code this we'll do file service dot our title controller file service dot our description controller and then file service dot our tags controller right and now what we want to do here is we want to do a loop for a for Loop for a text editing controller which is called controller oops in our controllers so we're saying for each controller in controllers do something and all we want to do here is we want to do controller Dot add listener and then the listener that we're going to pass is a function that we need to make so we can just uh pass it blank for next now actually we'll let it default to this right now and then we're going to pass in a new function so we're going to create this function and this function is very simple as well we're going to just call it void and it's going to be called underscore on field changed and this says anytime the fields change do something and this is going to call a set State and a set state is very important this means that anytime information changes it's going to reload this page which reloads everything else or reloads the the context I guess is an easier way to explain it and what we're going to do here is we're going to do fileservice.field empty which we don't actually have yet so let's go ahead and create that we can go back to our file service and we're going to make a Boolean bull which means it could be true or false and we'll call this Fields not empty and we're going to check this later as well which is why we're are calling it here in our service okay so we're going to do we're going to do file service Dot Fields not empty and then this is going to equal to our file service dot titlecontroller dot text Dot is not empty and we want to make sure that the other ones aren't empty so we can actually copy this alt Z I mean copy this and make sure that our description controller isn't empty and we want to make sure that our tags controller is not empty and if they're not so if all of them are not empty this is going to pass in that they're not empty if they are empty then any of these are empty then it's going to pass in that one of them are empty so now what we can do is we can add The Listener to our controllers and that's done by just doing on field changed great and now we can still work them like normal but now they're actually throwing in another piece of information they're checking to see if they're not empty great and then because we're adding something to it we also want to get rid of it when it's done so we can come back up here and do dispose just like we did earlier we want to dispose of stuff that we're doing so we can go ahead and just remove the listeners um actually we gotta make a function for that so we'll make a function for that just like we did the add listeners we'll make a function for remove listeners so we'll do remove listeners and then here we'll make uh essentially the exact same so we can copy this and then instead of add listener we're going to just remove the listener great and then we can call that on our dispose um remove listeners okay so when it's being used it's going to call the ad listeners which we can now call add listeners and then when it's not being used it's going to remove the listeners and we can refresh and now our copy paste actually works and the reason why this works is because every time we type in data that's why I didn't work earlier every time we typed in data we're setting the state so it's reloading our page every single time we type something in and then that's why it worked if I typed it in and saved it it's like oh there's data in there but if I deleted the data and then saved it oh there's no data in there but this is what we were missing we were missing this set state which we could have technically done earlier but I wanted to do it like this because this is how we do it perfect so now that we're kind of done with this screen for right now we can go back to our file service and we can start working on our actual functionality of our app so first what we're going to do is we're going to pass in a file and then this is going to to Auto Import from Dart i o this file could be null so we want to add a question mark and then we're going to call it selected file and this means the file that we selected and then we're also going to pass an a string and this string is going to be a selected directory which is equal by default to nothing nothing is a string nothing that's how you do it that way and we want to make sure that we don't add final so now what we can do is we can create a function that actually saves our content so when we hit our save button we want to be able to save our content so to do this we can do void save content and we're actually going to call this outside of our function as well which is why it's not underscore like my other methods were because we are going to be calling this elsewhere and then we also want to make sure that this is a sync which means that it can do stuff inside of it so we're going to pass in a few things that we're going to need first we're going to grab all of our controllers so we can do final title equals title controller dot text we're also going to do our description uh description equals description controller dot text and again we're grabbing the text not the actual controller itself and then final tags equals tags controller dot text perfect and then we want to create a new um we want it to contain create the con the text content that we're going to add to a text document and we can do this by doing final text content is equal to a blank array now what we want to do here is we want to style this how we want so there's many different ways that you can style a text document but the easiest way that I found is we're going to do the title which is the title of our video and then we're going to do a backslash n and backslash n and this means new lines so it's going to add that in and then we're going to pass in our title so essentially we're going title return return write in the title and then we're going to do it again return return or new line I guess is what it's called and then we're going to pass in our description and this is very because it's in a string you don't want to add like spacings or anything because they're going to be in your design and it's going to cause problems so just do a description and then we're going to a new line new line and then we're going to pass in our description which we can do by doing the dollar sign and then we're going to do new line new line and then we're going to call it tags and then the tags is going to be new line new line and then we're going to pass in our tags so essentially what this is saying and I'll show you here just for an example where Pretend This is a text field we're writing title period period and then this is the title and then we're returning twice and then we're doing description and then this is oops and then instead of writing it here we're doing return return this is the description right and then this is how it's lined up in the text document but then we'll be able to break out at the the two returns that way we can bring them into our forms which is nice this is an easy indicator that hey let's separate based on these this this situation so now that we have the text content what we can do is we can start writing in our uh we're going to do a try catch and a try catch is essentially saying Hey try to do something but if I fail don't worry I'm going to catch that failure and then I'll tell you why and and this is how you write a try catch so try something if it fails tell me what went wrong with this e and then we can pass this e now just because we already know that we're going to fail we can actually do that right now and we're going to use our stack bar which we've already made so we can do snack bar utils and then we want to show a snack bar and then for the snack bar we have the con context again this is grabbing a different context but we're going to have the contacts from when we pass it into our save context make sure you're passing in context very important and then if we fail well we're going to need an icons dot error to let us know that it failed and then tell us what failed now there's many different ways that this has failed we could grab the event and then based on that add different ones but I'm just going to keep it very basic because if this fails it means the file was not saved do I know why the file is not saved possibly but at the moment I just know it wasn't saved that's all I the user care about was my file saved yes or no and this will say that it did not save and then what we can do here is we can go into our try and we can actually try to save our file so first what we need to do is we need an if statement we're going to check to see if our selected file I wrote fi old I want file there we go we're going to check to see if our selected file is not equal to null and by default it is null right there's no this is why we have the question mark here because it is null by default this is null and if this means that it's null it means that there is no selected file so what we want to do then is we want to await this is why we're using async we're going to wait for a selected file which could be null so we're going to pass in the exclamation point and then we're going to write as string and then we're going to write our text content perfect so what this is saying is if it's null if it's not null which means we actually have a selected file we're good to go we already have the file everything is good to go we just need to save the content so it's going to await that it's going to make sure that we have our selected file it's going to check again to make sure that it's not null because it could be null and then if it's not null here as well then it's going to write as a string our text content which this is a string title new line new line title new line new line description and yeah we're good we've already written our file if it exists however it might not exist because by default it does not exist so let's go ahead and make sure that it does exist so we can do that if it doesn't exist well now we need to do something else and what we need to do is well first we want to figure out how we're going to structure our actual file path now I already know how we need to do it so you could take the moment to figure out how you want to do this but we're going to do that and what I want to do is I want to make sure that I include today's date because when I save this I need to make sure that I can store this later maybe I'm writing this file in advance I want to be able to quickly do it by date that we can filter from top to bottom I'm going to be putting everything in a folder that's going to have hundreds of text documents so by doing it by date is going to be very easy so to do this we need to get the date for today and we can do that by doing final today date and we need to create a function that actually gets our date so we can do get today date and now we need to create this function so we can come down below and then we're going to do static which means it can't be accessed elsewhere string and then get today date and then this is actually just going to return in a function that allows us to get the date so we'll do final let's we'll do final now equals date time and this is going to Auto Import and then we want now we want that we want right now right this moment right this moment when it's called and then what we need to do here is we need to install a formatter so that we can actually format our date how we want to so to do this we can do final formatter uh equals date format and date format doesn't exist and date format doesn't exist because we need to actually import a package so we'll do flutter Pub add international great now we have the ability to format our dates so we can do final formatter equals date format now it's Auto importing that and then we want to give it the format that we want so for this to work in a folder structure it's best to do the year Dash two M's Capital which is zero format so zero one zero two zero three and then the day which is lowercase DDS great this will give us uh so it's going to take our uh this is going to be our formatter it's going to date format great now what we can do is we can do a formatted date so we can do final formatted date equals formatter dot format that's a function our method and then we're going to format the now so essentially what this is saying and then let's go ahead and return it so we can stop getting errors so simply put we're we're going to return our formatted date or a formatted date is going to use a formatter that we created which in this case is going to take whatever we give it and we're going to format it and this uh this this way like we're going to say hey whatever date I give you we're going to format it so then we format the now so this gives us today's date in a long string a different date time Etc and then we're going to format it where we just want the the year the month and the day in this format and then we're going to return that and now we actually have our today's date right here which is going to return the formatted date so then today date is going to equal this formatted date which we're going to call with a method of get today date great hope that makes sense if not let me know in the comments um it gets it gets a little tricky when you're trying to do different things but it's definitely fun and and once you get used to it it's very straightforward so next we're going to do is we're going to return a string and the string is going to be called a meta data direct path this is going to be the path that we want and we want it to be equal to our selected directory now at the moment our selector directory is nothing and at the moment metad data direct path is nothing so what we want to do is we want to check to see if it is equal to nothing because we can't save a file if it's nothing if it's not created you know not equal to anything so what we're going to do is we're going to check is it empty and if it is empty then we're going to make it not empty so what we need to do here is we're going to do final directory equals and now we need to install another package and this package is going to be a file picker so we can control tilde do flutter Pub add file underscore picker and this is what makes uh flutter very easy because there's a lot of packages out there that you can use to do what you're trying to do so now we can do a file final directory equals and it's going to be a sync so we need to await it and it's going to be file picker Auto Import dot platform which is going to get my platform and then we're going to call its method get directory path and what this is saying is if it's empty we want to prompt the user to pick a file and grab the directory path is essentially what that's and you'll see that later but that's essentially what that's doing and now that we have a directory because we just selected a directory we want to do selected directory is equal to our meta director metadata direct bath which is also equal to our directory exclamation point and this confused me I didn't know what this meant but what this is saying is it's grabbing our directory and it's going to equal to both of these that's all it is so think of it backwards and because this could be null AK are um file picker does not choose a directory we need to make sure that we add the exclamation point because this could be null now we are getting an error right here and it's because the value of type string can't be assigned to a variable type file um oh and we're getting an error because we actually don't want to set this to our selected file we want to select this to our selected directory that's my fault and then we are getting an error because when I hit save it set it as a final again sometimes it causes problems because I have it auto saved to add final and const whenever it should uh but yeah so make sure it's underscore selected directory equals metadata direct path which is equal to the directory and we're going to make sure that it's not null it's not null then past that perfect because it needs to be a string strings can't be null great so now that we have that we're good in that section but sometimes again this is if it is empty we're going to essentially just create a directory but if it's not empty which means we already have the directory what we can do is we can do final file path and then we're going to pass in our information to do our path so we can do this by doing a string then we're going to pass in our path so our path is going to be our metadata direct path we're going to have a slash because that's how it is with the if you look at a you know how your computer's paths work and then we're going to pass in today's date today date we're going to do a dash space Dash we're going to pass in the title and then we're going to pass in whatever we want and then this for this because how I have it set up for my personal preference we're going to do metadata.txt and essentially just to show you what this looks like it's going to be like my path you know uh spellthorne right and then let's say it's on my desktop assume that's the correct path well what it's going to do is it's going to do today's date in that format so it's 2023 uh Dash because we have the dashes here uh zero four because it's April and then today's date is the 30th so it's 30 and then it's going to do this is the title and then it's going to return metadata.txt and make sure that you have the dot txt because this is going to tell your computer that this is a txt file or text file if you don't have that it'll just it could still work but make sure you have the dot txt very important and then whatever else you want is your path great now we can do final new file and then this file is actually just going to be a file and it's going to be a file of our file path great and then we can bring it all together by doing a weight new file we're going to write as a string just like we did before because now this is actually saying hey we have it and there we go we can now write a file so let's just break this down because I know it is a little confusing so essentially we're going to try to see if we can save our file if we don't save our file we're going to throw an error and it's just going to be a snack bar that says file not saved however if it is successful and doesn't throw an error then we're first going to check to see if we already have a selected file if our selected file is not equal to null this means we already have a file then we're going to just take the file we already have and write our text content which is right here into this file as a string if however we don't have a selected file we never created one yet because by default we don't then we're going to start creating one so we're going to get today's date so that we can add it to our directory again we use it right here we're also going to set up our director 3 path and we're going to grab in the selected directory that we already have by default we don't have one this is the first time we've used this app we don't have a selected directory so at that point if that is true if it's empty then we're going to a prompt our user with a file picker and let it choose a folder that you want and then what we're going to do is once you have chose that folder which is going to be right here is our directory we're going to save it into our metadata metadata direct path as well as our selected directory so now our selected directory knows that we have one and our metadata a direct path knows that we have one so this is now no longer true and we can continue so then we're going to create a file path with our direct path the today's date the title which is the content in our text editor in in our input for our title and then we're going to add in whatever we want to create a text document and then essentially we just have a new file which is going to be the file function of our file that we imported and it's going to just you know grab that file as an and to create that as an actual file and then it's going to take that new file that we just created and it's going to write that content text content as string hopefully that makes sense if not let me know in the comments and then what we're going to do is because this is successful we've now created a file saved the file and it is successful we just want to let our user know that it was in fact saved so we can do that by passing in snack bar utils show a snack bar we're going to pass in the contacts that we have this time it's going to be a successful so we'll do icons dot check underscore Circle because that's the one I like and then the message we're going to say file saved successfully great and now this actually allows us to save content which we can actually use by going back to our home screen and we can come back down to our saved file and instead of passing in a blank function now we can actually pass in the function that allows us to save it first so we want to make sure that our file service file service Dot Fields are not empty we want to make sure that they're not empty I don't want you to be able to save unless it everything is filled out title description and tags I'm not going to let you save until you gave me the title description and tags and if that's true then we can return a function that says it's true well this function is going to be an arrow function that calls our file service dot save content what we just created and we're going to pass in the context again this is where we're passing in the context that we're going to use later to make sure that we have context as well as for our snack bar and then if that doesn't work AKA they are not empty then we're going to just pass in null and the null should disable our button perfect so now when we have content our save button comes actually here and I saved it save button again let's rename that to save file our save file button actually works but if any of these are empty we are not able able to actually save our file until all of them and then if we hit save file this is actually going to pop up a window for us to be able to save our file and we'll select our folder file successfully saved and if we go to it right here it is it's the year the month the day s which is our title and the mid metadata and then I have dot txt so it's a text document and if we open it up here we go we have it exactly how we formatted it title uh to you know two new lines s two new lines description two new lines s two new lines tags well you get the idea and that's awesome but we're not done yet because now that we have the ability to save our files we also want to be able to make a new file we want to change our folder if we already have the folder selected and then of course we want to load our file so let's start doing that as well okay so we can go back to our file service now that we've successfully saved data what we want to be able to do is we want to create other we want to be able to load data so we can do that by coming out of our first save content make sure you come out of that completely and then we're going to do void load file and then this is going to pass in our context because we're beginning using a snack bar and we want to make sure that this is async as well there we go and now we can start doing this and this is very similar to the other one we're going to start off with a try catch because we want to handle our errors if we have to so to try and then we'll just catch and the catch is going to pass in a variable we don't actually use this variable but again you can if you want to it'll tell you what went wrong and you can make different snack bars for that but we're going to just keep it very basic if it fails it fails I I don't know why it failed it just it failed and I'm just going to tell you that something went wrong so we can do another snack bar utils dot show snack bar pass in our context we're going to do icons because this is again a failure so error rounded just like before and then this one is going to be no file selected so you did something wrong you didn't select the file that's completely fine you're not going to break my app but I'm going to let you know that you did not select a file before you continue and now what we want to do is we want to actually check and actually be able to get a file so we can do this by doing file picker which we installed earlier dot result this is saying hey this is the result from the file picker and we're going to add a question mark because it could be null because they could not select it and then we'll do result and then this is going to await uh file picker dot platform just like before but then this one we're going to do pick files and this essentially just says Hey lets you pick a file because we're going to load up you know we're going to click this button it's going to say hey pick a file and then whatever you pick is going to be the result that's essentially what's happening however we could fail that right so first what we want to do is we want to check to make sure that result is not equal to null if it's not equal to null then we you know if it is null we want to do something else if it isn't null then we want to use it because we have it so if it's not equal to null we can grab it so we can do file equals file and then this is really long it's result.files.single dot path and essentially this is just saying grab the first result and and give me the path for it and this could actually be equal to null you can see this right here string question mark so if that's ever the issue make sure you add an exclamation point at the end of whatever you're calling so it says hey this could be null and then what we want to do is now that we have our file we just want to save it to our selected file our selected file is going to equal to our file now we need to get the content so we can do final file content equals a weight file the file that we just made and then we want to read it this time before we wrote it we you know we wrote the data now we want to read the data as a string perfect now we're going to get all of our data as a string however we want to split the string up into different information so that we can put it into our input Fields so to do this once we have it we can do final lines because it's going to give us everything and we want to split this up so we can we already know what we're going to split it we're going to split our file content dot split and we're going to split it with the pattern that we used and the pattern that we used are the exclamation backslash n backslash n there's a reason why we did that one it makes it look really nice in the text document if you're reading the text document but two it's something that we always do after each section so we can go ahead and just grab that information because we separated it now we've used this a lot if you look we have it at the titles then we have n so this is our zero this would be our one this is our two actually I'm sorry this is zero um this is one yeah this is two this is three this is four and this is five so what we want to do is we want to grab just those lines because we don't need the other information that's just for a text document in case we're reading it that way what we want to do is we want to grab the individual lines of the actual data so we can do this by doing title controller dot text now we're actually submitting data from code into our input and and then we can make this equal to lines and we want the first one the first zero it goes from zero up so it counts from zero so the first one was actual our title I'll show you again this is zero so but we don't want this we want this one we want the actual data and that's why we're doing that one so we're going to grab one three and five essentially and then we can do descriptioncontroller dot text equals lines three and then we can do our tags tags controller dot text again make sure it's the texture changing lines and then the fifth one so we want the first line uh the first line which is technically second line third line and then the Fifth Line and now that we have this information we can say hey the file was successfully uploaded and we know how to do this because we made a stack bar so snack bar utils dot show snack bar pass in the context this is going to be successful so we can do upload file there we go and then we can do file upload it now we already know technically the file was uploaded because it changed the data but let's say the data was almost identical you wouldn't have known if it actually changed it or not however this could fail because again our result could be null and if a result is null then we want to do an else statement and then this is just going to be a snack bar utils dot show snack bar and then this is going to be an error because we didn't choose anything so error underscore rounded and then this message if it's null it means hey you did not select a file which again is completely fine it's not going to break the app but I want you to know that you did not select a file so if the try catch fails we did not select the file if the we did choose a file but it was null which means you didn't choose a file you had the opportunity to everything went right for you to choose a file and you chose not to then we're also going to get this result as well no file selected great now we can go back to our home screen and we can actually call the load file so we can come up here in our action button instead of returning null what we want to do is we just want to call file service Dot and then we just want to call that new file Dot load file there we go and then we're going to get an error on this uh checking to see oh we need it as an actual function there we go Arrow function can't just call it Arrow function and then save and then we can add this just so it's a little easier to read perfect so now when we click this we're going to click the button it's going to pop up our desktop and we could change the folder of course find out where a file is but if we grab the file let's go ahead and delete this stuff out right this is the file I have so if I click here I'm going to choose the file that I saved earlier because again you want to choose a file that's matching your folder structure file structure if it doesn't it's just going to mess up but we're going to choose a file that we've already saved earlier and there we go file uploaded and it put in that data but now that we have that file we already have the file we can this is a new title we can re-save that file and if we go here and actually open up this file just to prove that it's changed this is a new title and that's what I love so much about reading and writing data so now that we've saved the file we can delete this out right we can load that file back and it just grabs that information right back which is great now what we can do is we can work on the new file button I think we'll do the new file just because it's simpler so we can do void uh new file and then we'll pass in our context because again we're going to make a new uh show a snack bar anytime we're showing a snack bar we're passing in the context and then this is essentially just going to clear everything out so what we can do is we can do underscore selected file this file is going to be equal to null because again we check earlier if it's null and if it's not equal to null then we do stop if it is null then we create it again and we want to be able to do this so we're going to do selected file is equal to null but then we also want to clear out all of our controllers so we can do title controller dot clear we can do description controller dot clear and then we can do tags controller dot clear perfect and then because we've cleared everything and it was successful we do want to show a snack bar so show snack bar context icons dot you can just do file upload again we can choose this a different font if we need to but that's fine it still shows a file icon and then we'll do new file created perfect and then we save and now we can go back to our home screen and just like we called the load file we can come back to our main function and then instead of passing in all this time we can do file service dot new file and there we go now when we click this it deletes everything out and tells us that a new file has been created now it doesn't actually create the file until we actually save it so just keep that in mind but now it does save the successful file and it didn't prompt us to a different folder however if you look here we do have a different file and that is really awesome so it just kind of keeps the last folder that you had I feel I'm always going to use the exact same folder with this tool um or app but you could make it where you want to change the folder so that's why I have a change folder button but yeah if we don't change the folders just going to use the last location that we had which is really nice and then let's go ahead and we can clear it out again make a new file and we're good to go so now that we have all of that done we can create a new file we can save the file we can load a file we just want to be able to change our folder so we can do that by going back to our file service and then make a method for changing the folder to do this it's very straightforward as well we're just going to do a new void new directory this is going to pass in our context because we may do a snack bar and then we're going to do async because we're going to need a stuff that is asynchronous perfect now for this we're going to do the try catch again so we're going to try something first and then if it fails we're going to be there and we're going to catch it and let you know that it failed so we can do try catch uh toss in the E and then anytime we use the try catch we're going to let them know AKA our user some feedback so we can do the snack bar utils dot show snack bar pass in the contacts that we're passing icons dot error rounded I'm using the same one you already know that and then this time no folder selected so something fails it's because no folder was selected something else went wrong but the main issue was no folder was selected which is all we care about as the user I don't care what went wrong was my folder selected yes or no and it was not now if it is successful what we can do here is we can do a string this could be null so you want to pass in the question mark and we'll call this directory and then what we can do here is we can await our file picker again just like we did before if there wasn't a file we had to do this but now uh folder but now we do have a directory so we want to change it though so we're going to do the exact same thing again platform dot dot get directory path and then here we're going to essentially just do what we did earlier selected directory is equal to our directory and then our selected directory selected file excuse me selected file is going to be equal to null and this is why we're going to create a new folder but we're not going to have a file here and we are getting an error on the directory because the directory again could be null so because it could be null we want to add an exclamation at the point so it handles that hey this isn't going to work properly this isn't all perfect and then because this is successful this time we just want to pass in our spec bar show snack bar this one is going to be icons dot folder and then the message is going to be new folder selected perfect and there we go now we can go back to our home screen and we can come down to our folder button and then just like before fileservice Dot new directory and now when we click this folder we can choose a different folder let's go to our downloads hit select folder new folder has been selected now if we save this this is a new file description is I don't know tags or tags we can save this file and then if we go to the new folder just to show it to you we can actually go to our desktop actually that's not good let's go to load file we can go to our downloads and right here we have our new file that we just created in our downloads other than the one that was in our desktop perfect and there we go we did not select a file this was a fail error we did not select a folder this was a fail error we um hit new file we can do it this way save file it actually saves successfully because it's our first time but if we refresh it because we haven't saved anything yet new file save it where do you want to save it I hit cancel file not saved and there are are all of our save files and our error handling and all of that stuff and I know it's a little tricky to get the hang of that I'll probably do another video where we save do reading and writing data but that's essentially how we do it it's very straightforward so I think we are almost done with the actual functionality let's just make sure everything is cleaned up and good to go formatted properly we're we're adding our listener we're disposing them we're adding our listener we're removing them or on fields are changed everything has a function on our buttons file service new file load file directory save content everything looks good to go all right so we're pretty much good to go now what we can do is we can start styling your app a little bit better we want to add a splash screen to our app that loads at the beginning just to add in a nice little bit of flair so that it's not just loading right to this when we refresh it so we can do that by going over to screens new file this is going to be called Splash underscore screen dot Dart we're going to import our material like we normally do here we're going to create a stateful widget very important that it's a stateful widget and we'll call this splash screen there we go and then to actually test this out we can go back to our main.dart file instead of our home screen we can bring in our splash screen and there we go it's now a placeholder and now we can start styling our splash screen so for splash screen we're obviously going to return a scaffold our scaffold is going to have a background color we already have this which is our Dart app Theme dot Dart there we go uh we're then going to do a sized box just to make this a little bit easier we'll do body size the Box our sized box is going to have a well actually I'll show you in a moment why we do this we're going to add a child our child is going to be a column uh we're going to get an error on the const there we go our column is going to take some children the first child we're going to take is going to be um our icon our icon is going to be icons dot edit which is little pencil we're going to pass in a color which is going to be our app Theme accent and then we're going to pass in a size and the size is going to be 200. there we go there's a little pencil and then we're also going to do text our text is going to be meta tube and then we're going to add a style to this and we don't have a style to our text yet so we can go clean these up and go to our app Styles and then right below our counter style We'll add our last one const textile and we'll call this Splash style equals text Style and then we're going to pass in some styles so this one is going to take in a color which is going to be our accent color it's going to take in a font size of 60. a font style this time we're going to make it a font style dot italic and then our font weight is going to be font weight w500 which is like a medium then we can save that and then we can come back here and then do app Theme dot Splash Style great and there we go now we want this to be in the centered so we can do this by going to our column do main axis alignment main axis alignment Dot Center and then this centers it vertically however we want to also Center it horizontally which columns do by default however we need to give our sized box and this is why we made a size box we need to give our size box a width and this width is going to be double dot Infinity which means infinite essentially it's going to be as big as possible as as big as it can be forever and in this way it's always in the centered even if we scale it perfect and there we go now what we need to do because this is a splash screen we need it to move after a while so what we can do is we can come under our State we can do an init State here which is going to run as soon as the app starts and then we're not going to write too much here so we can just uh write it in our init State we're going to call a future dot delayed and then this is going to have a duration and then that duration is going to be seconds and we just want one second in my other video I made a video about uh doing Splash screens and I did two seconds but it just it was it was way too long so we're only going to do one second here and then what we need to do is delete that what we need to do here then is we're going to pass in our function and then this is what happens after one second it's very simple we just want to navigate to our other screen so we can do Navigator dot of context dot push replacement and normally you push stuff but we want to push the replacement which means we don't want this here anymore after we push it and then we're going to return a material page route and this material page route is going to take a builder we don't actually need to use the Builder so we can do underscore and then an error function and then we just want to pass in our home screen and what this will do what this will do is after one second it'll switch from our meta tube to our app there we go one seconds long enough for me to read it and then gone read it and gone perfect now we are done with our splash screen we're pretty much done with our app what we want to do is go to our main.dart file and we want to start messing with our window information because this is a window and we wanted to handle it specifically so we can start doing that in our main.dart file with our main.dart file anytime we're taking control of stuff we want to call widgets flutterbinding dot ensure initialize this just makes sure that widget uh the widgets are being built I think I don't actually know exactly what it is so let me know in the comments below but um this is kind of you know sometimes you just pipe code that makes sense but you don't know exactly what it does but maybe that's a No-No but that's what we're doing here and then we want to do uh we want to call in a new package and that package is going to be called window manager so control tilde flutter Pub add window underscore manager and then this will allow us to add like specific sizing and and all of that stuff great so we can do that now we can do a weight uh window with a lowercase manager dot ensure initialized and we're going to get an error because we're using a weight so we need to add that to our void Main and then we can call it that way and then we're going to get an issue on the window manager so import the library perfect now we want to give it some window options so we'll do window options window options lowercase equals window options higher case app capital and then we can give it a minimum size our minimum size is going to take a size and this size is going to be 400 by 780 780 is the height that I want it to have 480 is the minimum width that I want it to have that we can still make it a little smaller but I don't want it to start like that I personally like my size to be size and then 600 by uh 780 but let's say there's a reason why I want to make it smaller I would like to have the ability to do so so we're going to give it a minimum size which is 400 by 780 but then a size of 600 by 780. we also want this to start Center maybe in a future video I'll show you how you can make it where it saves the location uh on your on your screen but right now I didn't this video is way too long enough so we'll hold off on that and then we want to give it a title uh this title um we can actually just call Meta tube at the moment you can see it's lowercase meta tube but if we save this and then when we actually use it it'll switch it to Capital meta tube and then once we have our window option so you just want to use them so we can do window manager dot wait until ready to show pass in our window options and then pass in an async uh function we go and then we want to just wait for it to be window manager Dot show and then once it shows we want to focus it so we can do weight Window Manager dot Focus so it's going to show it and then it's going to focus it so that we can actually use it and then what we can do here is yeah just refresh up again an error don't refresh all right we got the good old close and reopen and uh yeah there we go uh that is completely fine there and then we are getting some issues on this so maybe my 780 is not the right size I think I know why we're running into that problem but there we go just refresh it and it will go ahead and do it and now you can see it's actually meta tube with a capital m and we actually want a capital T as well so we can refresh and then when we do refresh uh it does actually throw it into the center and it also shows our splash screen uh for a second and then goes we are getting an issue on the height because I think I messed up some of the uh Style on the home screen so to fix this we can just go into our home underscore screen.dart file and we can get rid of this height right below our main button for some reason it pushes it too high um not sure why I redid this design and it doesn't do that on my other one so for some reason that's different but that's fine and then uh the uh pop-ups still cover the save button which is fine because I don't want to be able to save while these are popping up anyhow so that's completely fine but that's why that was working so we can go back to our main.dart file and then of course our meta tube is now meta tube with the capital we still need to change the icon so we can actually do that right now um actually we'll do that yeah we can do that right now because we're pretty much done everything works now our app is completely finished uh all we really want to do is um is be able to change the icon for when we use it and then of course install it as an exe but everything works uh properly and we can save it we can handle our errors we can load new files which I'm not doing new file all of that stuff so what we want to do here is this gets a little tricky but first we need an icon so we can do that by loading up figma so here we have figma loaded up we just need to make an icon for our app and we can do that by going up to our plugins and search for for material oops go to plugins search for material design icons and hit run for this I'm just going to use a pencil which is right here and then we can close that out now we want to give this pencil our color so we can come down to the selection colors and that color was FFA 500 perfect and then we want to make this kind of big so we can click this little button right here to constrain the proportions make sure you're on the outer and not the vector inside but the actual pencil and then we can make this 512 this will just make a 512 image which is great and then we can get rid of any backgrounds and then there we go let me control R to resave this and we can call it app underscore icon and then we want to save this as an actual icon and not like a PNG or anything so we can go back up to our plugins and then this one is going to be called icns slash Ico generator and we can run this with our actual thing selected and then we can create an Ico and when we click this it's actually going to download our Ico so here we have our app icon what we want to do is we want to come over to our folder in our vs code we can right click any of them and reveal in file explorer and then we want to go into our meta2 folder itself we want to go to Windows Runner resources and in here you'll see another icon that says app underscore icon we actually want to just delete this out and we want to drag ours in and make sure that ours is app underscore icon there we go app underscore icon to replace the other app underscore icon now this doesn't really do much but what we can do is we can go back into our Windows uh folder go to runner go to resources and you'll actually see our icon right here which is great we don't actually need to mess with that now but what we do want to do is we want to go into our we want to go into the runner Dot RC and we want to scroll down and this is actually where it grabs the icon you can see right here icon icon but we want to come in here and we want to change this information so we can switch our company name to whatever you want it to be I'm just going to put spellthorne here for our file description we want to put um making YouTube metadata easier I guess um for our internal name metatube is fine for the copyright we're just going to put spellthorne um we can evendo.com if you want and then original file name is fine product name I guess we can keep it lower case but we'll just put it capital because I want it to look nice and then yeah so we can then save this file this is what we're going to use to do our build um so yeah that's pretty much it uh now we can open up our terminal and do flutter build windows and then this is going to build our app but it's going to make sure that you use that icon otherwise you're still going to get the flutter icon you'll still have the right name but you'll get the flutter icon so make sure that you change that information we're going to wait for this to build it shouldn't take that too too long but it does take a little bit alright so it's built so now what we can do is we can minimize this we can go into our folder we can go into build go to Windows go to runner go to release and here's our app and our app has the icon and uh we can actually open this up and this is a weird real working app like this we can close out of the default one this is our app we have the icon up here we have meta tube and it works exactly as we want it to we can now save a file uh let's do it on our desktop and we're going to save that file is going to pop up we can see the file here if we wanted to read it this way but why read it that way when we can read it our way we'll grab one that we did earlier the there we go it works perfect and it's also centered in the size and it works fine a little weird about the size but we can also make it bigger you just can't make it any oops you just can't make it any smaller than our minimum size so this is the smallest it's going to get but you can make it bigger if need be cool so now what we're going to do now that we have an exe we actually want to turn it into an actual installable application that you could share with yourself or friends and they can install it so let's go ahead and do that so to do that we're going to use a software called Inno and I will put a link to it in the description and what you want to do is you just want to go to the website and click the download Inno setup and then for us we have the exe and we can just download the US version and then that will open up just like a software and you can install it yourself once it's installed we want to actually open it up so we can do Inno setup compiler and then here we're going to actually tell it to use our files and create an actual will set up wizard for it so we can do that by clicking create a new setup file using the script wizard hit Ok We're then going to hit next we're then going to give our application a name which in this case is meta tube we're going to give it a version which is 1.0 we're going to put my uh publisher here because I'm the publisher but put your own name there we're also going to put my website which you can check out if you want to really just redirects you to my YouTube channel for right now but maybe in the future it'll be better and then we can hit next now the programs file is where we want it to install you can change this if you want but just put it in program files because that's where it needs to go and then the folder is going to be our meta tube we can hit next here what we want to do is we want to browse to our X executable which we can hit browse it's actually going to be on our desktop metatube then it's going to be in our build file our Windows File our Runner release and then select the meta tube that we created right here and then we want to add the files associated with our file so we can do that by hitting add files control and select these and then we can go ahead and add in a folder that we need as well there's a data folder in there we need to grab that so we can hit add folder and then we can go to our desktop metatube go to build Windows Runner release I wish this was easier and then make sure you select the entire data folder and then when you do that just hit yes and then we can double click the data folder which is going to be the last one and then right here in the destination subfolder just write data and then we can hit next then we can untick this we don't need a special executable we can then keep these selected and hit next we can do any license file I don't have a license I'll have to look into how to do that but you can add that information here uh we can do administrator install mode there we go we can do English and then here we need the custom compiler output folder this is going to hit browse so we'll go back to our desktop meta tube and then we're in our meta tube we're going to make a new folder just to keep it all together and we can call this installers and then we're just going to select that one uh the compiler output base file name we're going to put as ours and this is going to be meta tube make it sure make it the capitalization that you want and then we're going to create a custom setup icon file now we already have this icon file so we can hit browse go to our desktop metatube this one is going to be in our Windows our runner our resources and it's going to be the app icon that we use for our app icon as well so we can drag that in and then we can just hit next and then next and then finish and then this is going to say would you like to compile the new script now yes we do and then we can actually hit yes so we can save it later this is the script that we're going to use we can go back to our meta tube go to our installers and then just save it there and then we'll just call it meta tube ISS you can call whatever you want and hit save and wait for this to build it doesn't take that long because our app's not that big and now we can close out of this and then what we can do is we can go to our meta tube go to our installers and right here is our exe this is a real exe that will install our app so we can double click it and also if we right click it real quick go to properties and we go to details this is the information that we were typing in file description meta tube setup and that actually gets overwritten I guess so that's kind of sad but we could change that later and then product name is meta tube product version is one so I think the Inno actually overwrites this so that's kind of sad but that's okay we can double click it for a meta tube and then this is going to ask us to install it because it's an actual installation process which is awesome and then we can hit next and then I already have a folder but you won't and you hit yes and then we can do a desktop shortcut if you want and then install it and there we go there's our desktop application it's going to launch which is great it works but now we we can actually go to our Command Prompt and actually use it as an actual app which is awesome now granted if you share this with people they might get hey this isn't your app what are you doing this is unsafe so that's kind of why you need the license but that's it we took a while I don't know how long this video is yet but it took a while but we have a fully working app which is awesome the only issue is we might want to make this a little bit taller so that the buttons don't over cover the save file I think this is how I designed it initially so it doesn't completely cover it but for some reason it doesn't work exactly I did so we could just mess around with those sizing but that's it the file is I mean it works it's an actual real application we can install it and yeah I'd love to see what you guys would create let me know in the comments what you're going to make of course this kind of teaches you the basics of how to handle some things and you can definitely create this yourself I think it's very great to have this if you're making YouTube videos you can just copy paste into your YouTube video but yeah I hope you guys enjoy this video I worked really hard on this because it is something that I wanted and that's what's so great about flutter you can make stuff that makes your life easier but I also wanted to share it with you guys so that you can make something that might make your life easier that is going to use these uh you know these functions and these fundamentals so I hope you guys enjoyed this video definitely let me know if you have any issues in the comments below I'll try to help you out and I'll see you in the next one
Info
Channel: Spellthorn
Views: 16,949
Rating: undefined out of 5
Keywords: Spellthorn, Flutter, Desktop Application, Windows, MetaTube, Video Metadata, Widget, Service, EXE, Data Handling, GUI, Dart Programming, Cross-Platform, App Development, UI Design, Software Engineering, Flutter Framework, Desktop Development, Windows Development, Flutter Widgets, Flutter Services, Dart Programming Language, Flutter UI Design, Flutter Desktop Tutorial, Desktop App Development, YouTube Metadata, User Interface Design, Cross-Platform Development, Software Development
Id: SmmHdxAw8wA
Channel Id: undefined
Length: 106min 34sec (6394 seconds)
Published: Tue May 02 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.