ALL THE DASH MERCH: Building the DashShop | Learning to Fly - read the full article about Flutter, Mobile App Development and Native and cross-platform solutions from Flutter on Qualified.One
[MUSIC PLAYING] KHANH NGUYEN: Oh OK.
Lets go buy this.
Wow, that was really fast shipping.
My merch is here.
[MUSIC PLAYING] Hey, yall.
Welcome back to episode three of "Learning to Fly." In this episode, well go over a bunch of changes and improvements that have been introduced to our MyDash app since the previous episode.
Then well go ahead and jump into the highlight of this episode, the all new DashShop, where well take a look at what a theoretical merch store for Dash would look like and how I would implement it.
Of course, it wouldnt be learning to fly without hitting some turbulence along the way.
So well also talk through some of the problems I ran into and how I resolved it.
And finally, well wrap up with some questions for Fitz.
Lets get started.
[JINGLING SOUND] In the previous episode, we went over our fancy new Dash theme.
We looked at the dashboard UI and discussed some of the road bumps that I had run into, including but not limited to the bottom navigation bar.
[JINGLING SOUND] Since then, I took some of the notes that we got from the last episode and made some changes to MyDash.
[JINGLING SOUND] First off, I was able to resolve my issue with accessing my Dash theme colors.
As some of you pointed out, I had a row of consts that I had overlooked.
[JINGLING SOUND] Furthermore, based on another suggestion, I pulled my Dash theme into a separate file, so that its more organized and doesnt get all cluttered up in the code.
Finally, from the discussion with Fitz, my comment now is, well, more properly formatted and wraps around underneath the username thanks to rich text and text span.
[JINGLING SOUND] While I was at it, I also changed the username so that it distinguishes between post captions and comments just a little bit more.
[JINGLING SOUND] Finally, I pushed it as low as possible at the dashboard level just like how it appears in the app, just above the card level.
[JINGLING SOUND] Now, with all that covered, we can jump into the DashShop.
When I thought about building a Dash merch store and what it would look like, this is what I came up with.
And this here is the coded-up Flutter version.
You have the main shop page where theres a GridView of cards containing an image, name, and price for each of the products.
Theres a row at the top for the typical filter button in the search box.
But shh, dont tell anyone, it doesnt really do anything quite just yet.
From there, we can tap on one of the cards and be taken over to the product page.
The neat part here is that I was able to use the hero widget to animate from the shop page image to the product page image.
It took about a whole minute for me to watch the "Widget Of the Week" episode for it.
Well link to it up there as well-- and another minute to add the code.
And voila, it just worked.
[JINGLING SOUND] As for the product page images, theyre rotating through using a carousel slider.
The size selector is a toggle buttons widget and a dropdown button or the quantity selector.
And of course, an elevated button for our must-have add to bag functionality.
Now lets say I wanted to buy a sweatshirt in size medium.
I only want one for myself.
I hit Add To Bag, and it jumps me back to the shop page.
From there, we can tap the Bag button, which then will take us to our, well, our bag.
And there youll see our final page, our shopping bag with all of our stuff.
The shopping bag is fairly simple.
Its made up of a list view of cards, again, for the product previews.
You also have the price calculations at the bottom.
And finally, a Checkout button.
So when you hit checkout, itll jump you back to the shop page and clear your cart.
Youre probably wondering, Khanh, why? Thats not how checkout is supposed to work.
Well, thank you for asking.
Lets jump to the decisions and considerations portion of this episode.
[JINGLING SOUND] I had left out the checkout process because I would personally always want to use a payment processor package for that portion of the app, like Flutter Stripe.
On the same note, a Flutter cart package also exists, but I decided to build my own cart logic, because I thought it would be a good opportunity to write and learn some non-UI code.
Bag state lives at the shop level of my app.
The inherent problem here is that the bag doesnt persist if I navigate away from the shop page.
So in every other scenario, state management would be important here.
I suspect using a package like Hive for a NoSQL database would be a nice integration to have.
[JINGLING SOUND] With all that said, I also made a lot of assumptions that I would not have made with a real production-ready app, like assuming that there will always be one product image for every product in the shop.
This one would be relatively easy to get around by checking if the product has an image.
Otherwise replace it with a default image.
The shop has easily been the most complex part of this app that Ive worked on so far.
So its no surprise that Ive run into the most hurdles while building it.
[JINGLING SOUND] Luckily, as Ive been learning Flutter, Ive usually been able to look up the thing that I want to do and then just get an idea of the direction that I want to go in.
[JINGLING SOUND] My problems most of the time end up getting solved the same way as well, from figuring out why Flutter was yelling at me about, the argument type color cant be assigned to the parameter type material state property, to the exception that kept getting thrown for, incorrect use of parent data widget.
Two Google searches later, I found out that I needed to wrap my color in a material state property all, and that I had a rogue expanded widget that wasnt inside of a row, column, or a flex.
So removing the expanded widget was the answer.
[JINGLING SOUND] Thats not to say that I didnt run into issues that took me forever to figure out.
Two examples, number one, left-aligning a bunch of text within a column.
I truly didnt think I would struggle as much as I did.
After a long while googling and fighting with my code, I settled for wrapping the text in a size box that takes up the entire width and then set text align to TextAlign.left This method still feels a little hacky to me.
So Im guessing theres probably a better way to do this.
If you have any recommendations, please drop a comment.
I learned that list views also have a default padding, because there was a huge gap in my bag list of items and the top header.
I just couldnt figure out why there was so much white space.
I also kept getting an overflow error on the cards in my GridView.
But adding a size box was no help.
The answer here as it turns out was the aspect ratio on my GridView.
The aspect ratio defaults to one-to-one.
So the height of the card is constrained by the width of the card, which my card was very much not expecting.
And finally the one problem that I cant seem to figure out, I cant add my entire assets directory to my pub spec without getting an exception.
[JINGLING SOUND] I still havent figured this one out.
So lets phone a friend.
[PHONE RINGING] [MUSIC PLAYING] FITZ: Hello? KHANH NGUYEN: Hi, Fitz.
KHANH NGUYEN: Hi, this is Khanh.
KHANH NGUYEN: Hi.
So Im on "Who Wants to be a-- I mean, Im filming an episode of "Learning to Fly." but I have some questions that I would like answers for.
Can you help? FITZ: Yeah, absolutely.
Lets do it.
What questions do you have for me? KHANH NGUYEN: Cool.
So my first question for you is, well, Ive encountered this problem where in order for me to get access to all of my product images as an asset, I have to add each of the image paths to my pub spec.
If I try to add my directory just called assets slash, it throws an exception on the load async function.
Any ideas there? FITZ: Thats interesting.
Because you should be able to load a full directory.
KHANH NGUYEN: Mm-hmm.
FITZ: And Im wondering if-- so Ive seen sometimes the trailing slash makes a difference whether you have it or not.
KHANH NGUYEN: Mm-hmm.
FITZ: And Im also wondering if having a subdirectory in the assets helps as well.
And Im curious to hear more.
What did you experience, and what did you try? KHANH NGUYEN: Yeah.
So when I tried-- so originally, I had only just one image, it was a picture, it was like an image of Dash.
So I didnt really have to add a whole directory.
I was just saying, OK, let me just add this one image.
And that worked perfectly fine.
And then once I started building the DashShop, I started adding more product images.
And so I decided, hey, instead of having just this one image, just one image path, Im going to make a subdirectory within assets thats called images with a shop directory in addition to that so that I have all of the product images stored in there.
And then so thats when I tried to load in that directory.
And it didnt work out too well.
Because then it just, the load async function, it said something about the key was not loading.
So Im not really sure there.
[LAUGHS] FITZ: Thats very interesting.
And so when you have this assets folder.
Its just an assets directory in the root of your source folder? KHANH NGUYEN: Yeah.
I dont know.
Thats very interesting.
Youll have to follow up with me after you learn more about that.
Because I dont know.
It should be working.
KHANH NGUYEN: OK.
Well, let me troubleshoot that, and then Ill report back on the next episode then.
FITZ: Sounds great.
Look forward to the answer.
[LAUGHS] KHANH NGUYEN: All right.
So my next question for you is about my shop and product pages.
So right now theyre pretty tightly coupled.
The product page returns either a product or null.
So a product would indicate that the customer wanted to add that product to cart.
So the product then gets added to our cart that is stored on the shop page.
Null would indicate that they just want to exit the product page without adding anything to cart so that, well, it doesnt do anything.
Does that sound OK? What is the correct way to return data, say, from the product page to the main shop page? FITZ: OK, thats really interesting.
Because I think you want to think about what the purpose of each of those-- youre dealing with three different things here.
KHANH NGUYEN: Mm-hmm.
FITZ: Youre dealing with the product, the cart, and the main shopping page, right? KHANH NGUYEN: Mm-hmm.
FITZ: And so then, your question really is where is the functionality for adding a product to the cart and who is responsible for that.
And so thats something to think about here.
Because should the product be responsible for it adding itself to the cart? KHANH NGUYEN: Mm-hmm.
FITZ: Should the cart be responsible for adding a product to itself? KHANH NGUYEN: Mm-hmm.
FITZ: Or should the shopping page be responsible for adding a product to the cart.
And I dont know the right answer.
But I think once youve really determined that answer, that will change what you think about in terms of the returning from the product page into the shopping page.
Because right now youre using that return value to indicate whether it needs to be added to the cart.
And I think thats combining two different notions.
You have the navigation from the product page to the cart page, or the shopping page.
And you also have this idea of adding something to the cart.
And I think when you combine those two, I think thats where you end up with this question of is null the right thing to return, or is the product the right thing to return.
Im not sure.
And maybe the not sureness is coming from whos responsibility is it to add to the cart.
KHANH NGUYEN: Mm-hmm.
Actually, yeah, now that you mentioned that, Im starting to think it would probably make sense to just completely separate those transitions between pages.
So that the cart can handle just the, oh, theres a product were adding to cart.
So that way when we return, the shop page doesnt need to bother even thinking about what it needs to add to cart or what not to add to cart.
FITZ: Yeah, exactly.
The cart could be essentially its own notion of state.
And so the product could say, make a change to this state thing, which is add myself to this cart.
And then it doesnt have to worry about anything else, and the shop page doesnt have to worry about anything either.
It just gets the current state of the state of the cart state.
[LAUGHS] KHANH NGUYEN: Gotcha.
I think I got you.
Let me I think.
That is definitely one thing I want to go back and try to fix up then.
Because right now, its so tightly coupled that it didnt seem like it was a right way to do that.
So thanks, Fitz.
I think I got that down.
KHANH NGUYEN: So my next question for you is on the topic of builders.
So theres a lot of repetitive widgets in the DashShop, primarily building the cards.
I probably could have used more builders instead of for loops that I used.
I read-- heard that builders are supposed to be more efficient than for loops.
Why is that? What is the rule there? Is there a place where a for loop should be used instead of a builder? Is there a rule of thumb that I should follow? FITZ: Yeah.
I mean, I think the rule is-- and its more of a principle than a rule.
I think rules are meant to be never broken, and principles are sometimes broken.
But the principle would be, use builders where possible.
And theres two reasons why.
One is that in cases like list views or grid views, youll get a progressive build of whats on screen or maybe just off screen slightly is going to be whats built.
When you just have a for loop building a static list, its going to build everything every time.
KHANH NGUYEN: Mm-hmm.
FITZ: Or you have to do some weird hand-waving in order to get it to only build some things.
And thats where the builder comes in, because itll do some of that hand-waviness for you of checking whats on the screen.
The other thing the builder will do is give you a new build context.
And thats important for when you need to use things like scaffolds, or detect if theres an app bar, or try to get the right navigator in order to navigate between your two pages, or something like that.
Thats important to have a new build context, which you wont get if you just use a static for loop list.
KHANH NGUYEN: Oh, OK.
I think-- right, the build context.
That makes sense.
So just as a principle, thats probably a good principle to stick by.
Not rule, its a principle.
KHANH NGUYEN: Let me go back, and Ill probably have to check for any for loops Ive been using, just to try to turn that into builder code instead.
KHANH NGUYEN: Awesome.
So my last question for you is not really a question, more so of just, I guess, a prompt.
Do you have any recommendations or feedback on the DashShop for me, whether that be code review, the UI design, or anything that you have? FITZ: Yeah.
I think I was looking through it before this.
And I think that theres two pieces of feedback.
One is there are only like three items.
I want more Dash swag items.
That would be great.
And I would love to buy as many of them as possible.
[LAUGHS] Thats one.
KHANH NGUYEN: Noted.
[LAUGHTER] FITZ: I just need more swag.
KHANH NGUYEN: All right.
FITZ: The second one is, I noticed some of your widgets were having a lot of code.
[LAUGHTER] There was many, many lines and some nested widgets inside of those build methods.
And sometimes, you have that one widget which was encompassing a lot of different things.
And I think we talked a little bit about that with the notion of whos responsible for adding a product to the cart.
KHANH NGUYEN: Mm-hmm FITZ: And so it looked like, from the code perspective, there was a lot going on in each one of these things.
And it might be worth trying to think about how to segment things out, how to break them up, and how to just partition things out a little bit, refactor them into some things.
KHANH NGUYEN: Gotcha.
Fitz, you are also being far too nice.
I think everything was just one huge build method.
FITZ: [LAUGHS] KHANH NGUYEN: So Im glad you called that out.
I will totally go back and fix that up.
In terms of cleaning that up, any recommendations other than if-- its a huge block of code.
Any suggestions where I should start to break that out? FITZ: Yeah.
Its hard to say in a general sense.
But I would look for making sure that a widget is responsible for one thing, and one thing only as much as possible.
KHANH NGUYEN: OK.
Do one thing, and do it well.
KHANH NGUYEN: Cool.
That seems like another good principle that I should live by when I built the Flutter code.
I think that was all the questions I had for you.
Thank you so much, Fitz, for coming by and helping out on such short notice.
FITZ: All right.
And feel free to give me a ring on my fancy smartphone here.
KHANH NGUYEN: For sure.
You will be my first phone a friend.
[LAUGHS] Thanks, Fitz.
FITZ: All right.
Good luck, Khanh.
KHANH NGUYEN: Bye.
[JINGLING SOUND] All right.
So that just about does it for this episode of "Learn to Fly." Thank you so much for joining.
And before we go, I do have a question for you.
What Dash merch would you like to theoretically see in the DashShop? You may see it in the next episode.
So that about does it again.
Thank you so much for joining, and Ill see you in the next one.
Flutter: ALL THE DASH MERCH: Building the DashShop | Learning to Fly - Mobile App Development