Wow, it's been a little while! Hi, everyone!
In the last episode of
I not only cleaned out my apartment
but also my code.
Then we took a small hiatus and did some more refactoring
on the two-episode crossover with Craig on
All three videos will be linked up there and in the description
in case you wanted to check it out and get caught up.
However, for now, no more refactoring,
we're back to building out new features.
In this episode, we'll be talking about my process
with building up a Dash chatbot, which I like to call...
wait for it... "The DashBot."
♪ [music] ♪
When I was thinking about the UI interfaces
that I use in my day-to-day life,
I'd already put together a newsfeed and an e-commerce interface.
So, naturally, the next step was a chat interface.
Who better to talk to than Dash?
Thus, the DashBot was born.
We can say, "Hi, Dash."
We can ask Dash what today's date is,
ask Dash to tell us a joke,
or even ask Dash for a Flutter video.
Anything outside of that and Dash just says random things.
Like the rest of the app, I wanted to focus on the UI,
so I didn't spend too much time on the backend.
As a result, my DashBot has pretty bare-bones functionality.
I faked the chatbot by putting together a DashBot class,
which takes some input text, looks for keywords,
and spits back a response.
Wireframe in the UI for DashBot was a bit easier
than the other parts of the app
because there weren't quite as many moving parts.
You have the chat bubbles, a text field to type in,
and the Send button.
I also wanted to work with a little bit more than just text,
so I also added the message sender's profile picture
and link previews.
Going from wireframe to Flutter code,
I made the chat messages section at the top a ListView
which contains the list of messages.
Each message was a row with the chat bubble
and sender profile picture.
Messages containing a link are followed by a separate chat bubble
which has the link preview,
so those two chat bubbles are wrapped into their own column.
Then at the very bottom of the screen is a text field to type a message.
I realized I didn't need to use a row to be able to add the Send icon
since
I wrapped the icon in the
to trigger my
I cropped the sender profile picture to a circle, using ClipRRect.
I know there's already a widget that does this for me,
but to be honest, I was on such a roll coding
that I totally forgot it existed.
I think I just finished typing "BoxFit.cover" when it hit me.
Oh, well.
Anyhow, maybe I'll fix that in the future.
Don't worry, though, because I didn't actually try
to reinvent the wheel with the rest of the DashBot.
I hopped on over to
for my chat bubbles,
any_link_preview
and
to the AnyLinkPreview widget.
Though, one issue that I'm trying to figure out
is why my animation to scroll down to the bottom on new messages work
when I send a new message,
but not on Dash's new messages.
Given more time, I would have liked
to implement actual APIs in the backend
to have the DashBot be a little bit smarter.
I'd also format the link within the chat bubbles,
but the chat bubbles widget only takes a string,
so it would have required a little bit more heavy lifting
than just adding a TextStyle to the text widget
like I did for the dashboard.
So this is usually the point in the video
where I randomly drop in on Fitz,
but because I am a woman of surprises,
we're going to randomly interrupt Craig with questions instead.
So let's check in with Craig.
♪ [music] ♪
Craig? Why are you there?
Khanh, what do you mean?
Why aren't
Uh... Craig, I went home like four weeks ago.
Hmm...
Okay.
Well, that's not where I expected to find you,
but since I've got you on the line, I've got a few questions for you
that came up during my process with building the DashBot.
You have time?
Well, I've been here for four weeks, so I'm not going to leave now.
Perfect.
Then, Question 1 for you:
I used a
to automatically scroll to the bottom when a new message comes in.
But now I'm trying to figure out why it sometimes works
and sometimes doesn't.
Is there a different or better way to do that?
Yeah, that can be a tricky one.
I remember a long time ago, I also built a chat app
in a side project,
and what I did was set the reversed property to true
-on that ScrollView. -Hmm. Yeah.
And then you can always scroll to 0.
And that will always work
because sometimes when you're adding things at the bottom,
it can get a little confused.
-Oh, okay. -Of course, when you do that,
when you do that, you just need to, of course, reverse the order
of all of the widgets that you feed into the ScrollController.
Oh, okay.
But if you set reverse to true, and then scroll to 0,
I think that'll work pretty well.
Okay, that does sound a lot better because especially right now,
I think my code is probably a little bit more complex
than it probably needed to be, so thank you, Craig.
I will pull that into my code, and let's see if it works.
Cool, thank you.
So on to Question 2 then.
My ListView builder code for the chat messages
was particularly chunky.
So this is primarily because there were so many conditions
on how the layout should look.
For example, the profile picture should appear on the left
versus the right,
depending on who sent the message.
Or what color the text bubble should be,
again, depending on who sent the message,
whether there's a link preview that we should include
as a link preview.
It's just so many conditions,
and I just ended up breaking it out into several widgets
so there's less widget code now.
But is there a better way to approach this type of code
in the future?
I mean, overall, it's the same amount of code,
but just I have separate widgets so it looks less crazy.
Yeah.
Chat apps do... a lot of us, again, build these kind of intro chat apps,
but once you start to actually include
all the features in a real chat app,
as you've experienced, it balloons pretty quickly.
It sounds like what you did is pretty good.
You found the chunks that were maybe reusable
or just deep subtrees of widgets and broke those out into their own.
And now you're worried about the complexity of determining
how to bring them back together in that main build method.
And for that, I would just say,
eventually, some code is going to have to make these decisions.
Some code is going to have to check some conditionals and branch
based on the nature of the message or the nature of the whatever.
And if you're ever feeling self-conscious about maybe having
too involved of a widget that you've just made,
I'd encourage you to look in some of the material widgets build methods.
Mm-hmm, yeah.
They do a lot.
There is a lot going on, like look in the Scaffolds build method,
and it's enormous.
There's so much juggling it has to do to position everything just right,
if and only if these other things are or aren't there.
-Yep. -And that logic just has to exist.
-Mm-hmm. -There's no way around it.
So I think what you've written sounds pretty good.
Okay, cool.
And then so that leaves me to my last question for you,
which was any other feedback you have for me on the UI
that I guess, now that you're sitting there,
you've had a lot of time to review in the last four weeks, right?
Would you have built it any differently?
Well, the one thing that jumped out at me
because I think it's quite a strong chat UI,
you used the chat bubbles plugin or package,
which is very strong.
The one thing I did notice is that there's no timestamps
-on any of the messages. -Mm-hmm.
And that's a nice feature to be able to scroll back.
Maybe you sent someone a message on Tuesday,
and you're scrolling back to find it,
and you don't know how close you are to Tuesday yet.
Mm-hmm.
But the tricky thing about timestamps
is if you just add one on every message,
it can really clutter it up.
So some chat apps will-- they'll group them themselves
by messages that were all sent together.
They'll just get one timestamp,
and then if two hours pass before the next message,
-okay, we'll include another timestamp. -Yeah.
And that takes some more pre-processing.
That'll make the build method we were talking about before
even more complicated,
as it has to figure out when to insert a timestamp.
But I think that would be a big improvement
on the chat UI for the end user.
But you will have to accept that you'll be writing more logic
in that build method.
Gotcha. Okay.
So I'm thinking if I were to approach adding timestamps like that,
I could see myself maybe adding what's called, I don't know,
milestone timestamp or something like that
so that it could check to see, okay, when was...
like the logic should be
when was the last message that was sent
and then when's this current message,
and then in the case where if it's been over, say,
two hours difference or something,
just add in that widget and that timestamp.
Does that sound about right like what you're talking about?
Yeah, and I would recommend drawing inspiration from other chat apps.
Just open things on your phone and scroll through
and get a sense for when did that app think it was important
to indicate when the message was sent
because they've probably done a lot of research on it,
so just steal what they do.
Yeah, that's a good point.
Okay, that's cool. I think I'll try to check that out.
I believe the chat bubbles does come
with a timestamp option that you can enable
-but I will have to double-check on that. -Oh, nice.
So cool, thank you for reminding me of that.
Awesome. Well, that's all the questions I had for you, Craig.
Thank you so much for joining on such short notice
from
I guess I kind of interrupted you there,
but I appreciate you making the time.
Yeah, well, I've literally been doing nothing for a month
so this is my first time talking to a person.
[chuckles] Okay.
Well then, we'll have to catch up soon, Craig,
[laughs]
Sounds good. See you, Khanh.
Thanks, Craig. Now a question for you all.
If you're building out a DashBot,
what would be your must-have feature?
Also, bonus points, if you've watched
please let us know what you think.
Would you like to see more crossover episodes in the future?
Craig is awesome, and I love working with him,
so I'm really hoping that you'll say yes.
But that's pretty much it for the DashBot.
Thank you for taking the time out of your day to join me
on this episode of
and I will see you in the next one.
Bye.
♪ [music] ♪