ANDREW BROGDON: Hey, everybody. Welcome back to The Boring Show. I'm Andrew Brogdon
from the Flutter team. And with me is-- MATT SULLIVAN: I'm
Matt Sullivan, also, from the Flutter team. ANDREW BROGDON: Yeah. And so today we're going
to pick up right where Phillip and Will left off. We're going to build
on what they had done, and we're going to talk about
adding searching to the app. MATT SULLIVAN: Oh, cool. So this is the Hacker
News app that they built. ANDREW BROGDON: Yes. So we're going to be working
on the Hacker News app. And right now it
pulls down articles and puts in a list
view, and you can expand them and use
URL launcher to get out to the actual article. We're going to use some stuff
out of the material package to add some easy
searching functionality to the existing app. MATT SULLIVAN:
Searching is never easy. ANDREW BROGDON: Well, now-- MATT SULLIVAN: You're
going to prove me wrong. ANDREW BROGDON: Let's see. I think we can get this
wired up pretty quick. It's-- MATT SULLIVAN: Cool. ANDREW BROGDON: It's a fairly
straightforward thing to do. So if we look at the
code, material has-- let me go into
the API docs here. Material gives us this
nice show search function. MATT SULLIVAN: This is
going to be in the same vein as you have things like
show persistence sheet, show modal dialogue. ANDREW BROGDON:
Show modal dialogue is one I've used before, yeah. MATT SULLIVAN: So this
is a conditional one. Show search. ANDREW BROGDON: Yeah. See, there's some
top level functions just kind of hanging out
in the material package that you can call. And so this is show search
that I'm looking at right here. It takes a build
context, because you're going to be
displaying something, you need a context to
put it into a tree. And it takes a search delegate. And a search delegate is a thing
that does searching for you. So it provides kind
of a nice framework to basically get the
search functionality wired into the UI. And so let me go
ahead, pop in here. Quick note, in keeping
with Will's request at the end of our last
episode, I did change the font. We changed the font from
the sort of 1980s style to Garamond, which is a
little bit more newsy. MATT SULLIVAN: So we actually
have some like styling. ANDREW BROGDON: Yeah. We did a slight bit of
styling before this episode in keeping with some requests
from Will that he made. So it might look a
little bit different, but it's just a
font at this point. So we've got our app here. It uses-- it's got
a home page, and we need to wire in searching. So we're going to need
a search icon somewhere that people can click
on to trigger it. And we're going to need
this search delegates. Let me start-- let's
drop an icon into our-- MATT SULLIVAN: Why don't
we stick it in the app bar. ANDREW BROGDON: Stick
it in the app bar. I think we can go up here
and just do actions, right? MATT SULLIVAN: Yeah. One of the nice things about
the floaters implementation of the app bar is it gives you
a whole bunch of other widgets you can drop in. One of them is actions, which
will basically display things, I believe, trailing at
the end of the app bar. ANDREW BROGDON: Yeah. So we've got our Hacker
News icon on the left. So we've got in the
center our title, and this should go on the right. So let's do-- I'm guessing I
need an icon here. MATT SULLIVAN: Do you
want icon or icon button? ANDREW BROGDON: Let's see. I was going to go
with an icon button. We could do a straight
up like gesture detector and start with that. MATT SULLIVAN: Could do. ANDREW BROGDON: So
we'd have an on tab and I'll just give it
an empty one for now. And then child would be an icon. And so we give it-- I'm guessing-- yep, search. There's the Search icon. There we go. Put that in there. MATT SULLIVAN: Oh, and you
can preview the icon over on the reference side. I never noticed that. ANDREW BROGDON: You can do that
actually with material icons, not with the Cupertino
icons, believe it or not. So we have an open bug for that. That's a request I made of
the IntelliJ plugin team. Because I've been working
on some Cupertino stuff. MATT SULLIVAN: Cool. ANDREW BROGDON: But, yeah, you
get the little search thing right there. And so let's save that
and see what we get. MATT SULLIVAN: There we go. ANDREW BROGDON: Cool. MATT SULLIVAN: You know,
probably the problem here is that if you make that an
icon button that will give it more appropriate padding. ANDREW BROGDON: All right. Let's try that. MATT SULLIVAN: Because
just your texture's one way to get gestures on-- a whole range of gestures
on any type of widget. Icon button will basically
do most of the wiring up things like
the InkWell splash and all the other
bits and pieces for-- ANDREW BROGDON: That's right. All the other material eBits. And I think this takes
an on press like that. NT yelling at me. What have I forgotten? Too many positional arguments? Like that? OK. MATT SULLIVAN: If
you wanted to do double tap or long
press on an icon, then you'd use gesture detector. But-- ANDREW BROGDON: Or dragging it,
for some reason if you want. I don't know why you'd
want to start a drag-- one of your actions but-- OK. So we got-- we got
a-- can I click this? Yep. MATT SULLIVAN: Here we go. ANDREW BROGDON: There we go. OK. So now we got something we
can launch our search with, which is cool. Let's get the search
delegate in here. I'll put it-- let's just
put it at the bottom. So class, article search. MATT SULLIVAN: Sounds good. ANDREW BROGDON: And
I'm going to pass [INAUDIBLE] case this because
that's how we do things. And then it's extends, search,
delegates, which is a generic. And so you put in
the thing that you want to get out of the search. MATT SULLIVAN: Yes. So what type you want to
get out of the search. ANDREW BROGDON: Yeah. MATT SULLIVAN: So here we
need to make a decision. So when we search
for something, what do we want the action to be? ANDREW BROGDON: That's
a good question. MATT SULLIVAN: Because
what we could do is we could create a
separate page, and we could have a details page. Probably the easier
thing to begin with is if we search and get
the URL, and then we can use the URL launcher to-- ANDREW BROGDON: See
it pick a result and you just go immediately
to the article just as a sort of demonstration
of the concept. MATT SULLIVAN: But the problem
with that, potentially, is when the search
results come back, you're going to see the
URL and not the title. Do we have the concept
of an article class? ANDREW BROGDON: We do. MATT SULLIVAN: So
maybe we could-- ANDREW BROGDON:
Why don't we do-- MATT SULLIVAN: --return that? ANDREW BROGDON: --do an
article and start with that. And so that's going to extend-- I'm just going to put
a bunch of blank lines in here so I can kind of work
in the middle of the screen. And so we're being
yelled at because we're missing a whole bunch
of required overrides. Boom. MATT SULLIVAN: Build actions,
build leading, build results. ANDREW BROGDON: Right. So, yeah. MATT SULLIVAN:
Build suggestions. ANDREW BROGDON: What
the heck do these do? Fortunately, we have-- here. So we have-- this comes with
four different build methods. Build actions so widgets
to display after the search query in the app bar. So this is going to pop up a
new screen on top of whatever we had before that's
going to be our search. MATT SULLIVAN: So
this is the equivalent of using the navigator to
navigate to an entirely new widget tree inside the-- ANDREW BROGDON: Which it's
probably doing under the hood. MATT SULLIVAN: It
is because I think we're going to have to use
Navigator.pop to get back off the page. ANDREW BROGDON: Yeah,
that would make sense. Although, is there a-- oh, there's close method. MATT SULLIVAN: Or you could
just use a close method. ANDREW BROGDON: OK. So build actions,
build leading, which is the widget to
display before the text that you're going
to be typing into. So like a back button. MATT SULLIVAN: Yeah,
it's going to-- yeah, there's going to
be-- that's going to be the leading button on
the left of the search bar. ANDREW BROGDON: So that's
when we'll call close. MATT SULLIVAN: That's
when we'll call for-- yeah, so if we want to have
navigation back-- you know, those if you want to close,
the easiest way to do that would be to either
do the Cupertino little x in the corner, or to
have the Android back arrow. ANDREW BROGDON: So just for fun,
what if we just leave all those empty? I wonder if it'll
completely freak out? So show search is the
name of the function. Then I could just give it
an article search object. And that should be--
what else have we got? Oh, you're right. Unfortunately, I have one
because I'm in a builder. Take it those out of order. MATT SULLIVAN: You
might have to-- ANDREW BROGDON:
They're not positional. Search. Just delegate. Delegate. There we go. Now, I put my comma in
here so I can format, which always makes me happy. Bring my same back up. MATT SULLIVAN: I feel bad
things are about to happen. ANDREW BROGDON: Yes. MATT SULLIVAN: That just happen. ANDREW BROGDON: So it's not
kidding when it says to do. You need to implement this. So-- MATT SULLIVAN: The
question is, which ones are these is it going to need? ANDREW BROGDON: To get
going we could go-- I wonder if we could find
out where exactly it failed. Anyway, let's start putting
some things in here. So build actions. So we would have a-- so that's to the right. So if you wanted like a clear-- or something like that. MATT SULLIVAN: This
is the same as-- this is the same as the app bar. So you have actions
on the right and you have leaving on the left. ANDREW BROGDON: That's
why it takes a list. MATT SULLIVAN: So we
could return an empty list and it might-- ANDREW BROGDON: Let's just give
it some kind of an icon here. Is there a clear? Cool. OK. So that's one. Three to go. Build leading-- MATT SULLIVAN:
Semicolon or a comma. There you go. ANDREW BROGDON:
Gets me every time. There we go. MATT SULLIVAN: Don't you
just love backseat drivers? [INAUDIBLE] ANDREW BROGDON: You're
right, I can't-- you spotted an actual error so-- MATT SULLIVAN: You coded wrong. ANDREW BROGDON: --I
can hardly complain. MATT SULLIVAN: So I
can just-- you know. ANDREW BROGDON: You missed
the exit two miles ago. MATT SULLIVAN: So this
is a single widget. ANDREW BROGDON: Right. And so this is
the build leading. So this is where we could
return a button to close. MATT SULLIVAN: Yeah. ANDREW BROGDON:
So we tried that. And that could be
an icon button. Right. So that gets an icon. MATT SULLIVAN: See, it gives
icon.clear or .left back. ANDREW BROGDON: Is
there a row back? Like that. And then we need to
give it an on pressed. And that-- oh, it was
going to do closed, right? And close takes a-- MATT SULLIVAN: I think so. You need the
context and closed-- ANDREW BROGDON: Oh,
it gives me a context. OK. So I can use that. And-- MATT SULLIVAN: Wait. What does it give you? ANDREW BROGDON: Oh,
this wants the result. So we pass back a no? MATT SULLIVAN: Let's
have-- let's have a look. ANDREW BROGDON: Why don't
we go-- let's look at the-- MATT SULLIVAN: Oh, OK. So let's press make
null for the time being, because we don't have a result. ANDREW BROGDON: The return
value provided for result is used as a return value
of the call to show search. So if we want it, we had to pass
something back to be like, hey, they didn't care about
the search, right? MATT SULLIVAN: Yeah. So it could be an empty article
that might just take null. ANDREW BROGDON: Yeah. I think null would work. Does this build now? No? All right. MATT SULLIVAN: How about we
just ret-- we could return null for those two widgets. That might just be
looking for the return. Child is not equal to null. Which child? ANDREW BROGDON: Let's
just return a container. I'm worried that I've messed
something else up and I just think that I've-- no. OK. So there's that. That still has-- let's make
this an icon button, too. MATT SULLIVAN: Yeah. ANDREW BROGDON: So we
give it an icon like that. Then we need an on pressed. Let's just give it
an empty one for now. And capitalization helps because
this is not Visual Basic. There we go. No offense to anyone who
codes in Visual Basic. Gets a lot of work done. And what am I messing up here? That's it right there. MATT SULLIVAN: There you go. So does this mean if you
click the leading, what happens when it calls close? It closes. ANDREW BROGDON: Did
you see that, though? Watch. I swear I saw a little
bit of the red screen in there the first
time I did that. No. All right. MATT SULLIVAN: OK. We should-- we'll
have to watch the re-- ANDREW BROGDON: I'm
imagining things. MATT SULLIVAN: We'll
watch the rerun and see-- ANDREW BROGDON: Yeah. MATT SULLIVAN:
--what we messed up. ANDREW BROGDON: What
are we-- are we 30-- are we 30 fps here-- MATT SULLIVAN:
Comments below, please. ANDREW BROGDON: --for YouTube? I don't know. MATT SULLIVAN: We're surely
recording this is 60 fps because that's what
Flutter does, right? ANDREW BROGDON: I just moved
so quickly you can't really get the nuance at 30 fps. MATT SULLIVAN:
You're-- you're a blur. ANDREW BROGDON: Yeah. MATT SULLIVAN: So where were we? ANDREW BROGDON: Yeah. So we launched an empty
screen, and then I congratulated myself a lot. MATT SULLIVAN: Search
was typable now, right? ANDREW BROGDON: You should-- MATT SULLIVAN: Search bar. OK. ANDREW BROGDON: Curious why the
soft keyboard didn't come up. All right. We'll have to look
into that one. All right. So we have build results
and build suggestions. So how do we get the
current state of the search? MATT SULLIVAN: OK. Let's take a look-- ANDREW BROGDON: Let me-- MATT SULLIVAN: Let's
take a look at-- ANDREW BROGDON: There's
gotta be a way to do that. MATT SULLIVAN: API surface
and see what we're given. There is-- there you go. There's a property called query. ANDREW BROGDON: Here we go. OK. So we can do-- MATT SULLIVAN: I guess it-- ANDREW BROGDON: So
we'll have a query which represents whatever-- MATT SULLIVAN: Now,
the question is-- ANDREW BROGDON:
--people are typing in, so I should be able to
do something like this. MATT SULLIVAN: Text query. ANDREW BROGDON: Maybe. MATT SULLIVAN: And then-- OK. ANDREW BROGDON: So pop
up my search and do-- there we go. MATT SULLIVAN: Magics. ANDREW BROGDON: So
we do have data. We've got to connect
this to something. Oh, wait. That's a good point, too. So we have this little clear
button not clearing anything. Is there a way to clear this? I bet there is a
method for that. MATT SULLIVAN: And
let's have a look. ANDREW BROGDON: Clear. Or do we just go-- can we assign to query, as well? Does that work? It apparently does. MATT SULLIVAN: Wow. ANDREW BROGDON: So now
we're working clear button. Awesome. Thanks to the magic
of string assignments. MATT SULLIVAN: Search and
so we're going to have to-- so what do we-- we're
going to have a list of articles to-- to-- this is almost like-- more
like filtering the search. But I guess same thing. ANDREW BROGDON: Yeah,
that's a good point. How do we get those
into the search class? MATT SULLIVAN: Because
this is a sort of-- it's navigated to
a separate context. So, yeah, how are
we going to do this? ANDREW BROGDON: So we have-- I mean, we have
our block, right? That's where we get-- somewhere down here we're
using a stream builder. MATT SULLIVAN: OK. So we can use this-- ANDREW BROGDON: So
we have our block. MATT SULLIVAN: --stream builder. ANDREW BROGDON: We
could give our-- all right. So this is-- so the
list from-- so the body is a stream builder,
which means when the block updates
the stream, that's going to get rebuilt. Right. MATT SULLIVAN: So this is
coming from block dot-- where is block coming from? It's coming from a-- ANDREW BROGDON: Block is
given to us by the app, I believe, right there. So the app creates
the block here. MATT SULLIVAN: OK, so is it up? ANDREW BROGDON: Yeah. There we go. There is where the
block is created. MATT SULLIVAN: So we created-- ANDREW BROGDON: That's
given to the app. The app drills it down
into the home page. MATT SULLIVAN: Where do we
insert it into the widget tree? ANDREW BROGDON: So
it goes in right here as part of this, my home page. MATT SULLIVAN: OK. So when we call my home page-- ANDREW BROGDON: That's got a
working block at that point. MATT SULLIVAN: The block. OK. ANDREW BROGDON: And
so the home page state, which is the one building
the search, that can do-- MATT SULLIVAN: So
we don't actually-- ANDREW BROGDON: That could get--
that could get us the current state of-- see, if we're really
slick, we'd like update the search cla--
the search delegate class with like the
stream on the fly. I don't think we're
quite there yet. We could give it-- MATT SULLIVAN: How many
hours do we have for this-- ANDREW BROGDON: Yeah. This will be our first ever
seven hour Boring Show episode. MATT SULLIVAN: Yes. ANDREW BROGDON: We could
just give it as a parameter, because it can get it an
unmodifiable list view-- MATT SULLIVAN: So
we're going to pass it. ANDREW BROGDON: --of articles. So we could just give it
the articles like that. MATT SULLIVAN: Oh, when
we instantiate the-- ANDREW BROGDON: Right. MATT SULLIVAN:
Oh, that's clever. So we-- ANDREW BROGDON: So
meet up a final-- MATT SULLIVAN: Kind of wouldn't
want to do this in reality, because that list could be-- well, I mean, your search
could be coming over HTTP, it could be coming from
any sort of data source. We can pass this in. That's cool. ANDREW BROGDON: We need to-- you know, let's generate
a constructor for me. Boom. I always forget to use those
and they're right there. Command end. Visual Studio Code, I
think, has some key command you can do to generate
common stuff, too. MATT SULLIVAN: I'm sure it does. I should stop typing
these things manually and work out what
those bindings are. ANDREW BROGDON: I'm trying
to force myself to do it like I've been needing a bunch
of double equals and hash codes recently for some view model
classes, and I've been-- MATT SULLIVAN: Shouldn't you
just be using built value? ANDREW BROGDON:
I should be using build value for my view models. The problem is I like to
keep them in the class with the widget that's
going to consume them. And that's tricky because
of the way the build-- the built value stuff. As you've seen in some
of our earlier episodes, the build value-- you know, you
put your class in its own file, it generates a part file
that sits next to it. MATT SULLIVAN: Yeah. ANDREW BROGDON: And that
can be a little bit awkward if you want to have
anything else in that file. Works great, but you
have to structure your code a little bit
specifically for that. OK. So we have this. So now we can go back up here
where I now have an error and give it
widgets.block.articles, which is a stream. MATT SULLIVAN: Oh, you're
passing in the stream. ANDREW BROGDON: Is
this a value stream that I can get a value out of? MATT SULLIVAN: Gives a stream
of list of articles right now. OK. Because we're using stream. ANDREW BROGDON: OK. So I should be able to do
that instead of future. How to do this correctly. Because you could-- MATT SULLIVAN: Because there
will be nothing in this until such time the block
resolves the stream. ANDREW BROGDON: Right. Which isn't that big of a deal. We can check and be like, oh,
there's nothing in the stream yet so-- MATT SULLIVAN: Why don't
you use a FutureBuilder? ANDREW BROGDON: Would
we want to-- so say there's nothing in there yet
and somebody hits the search button, do we want to delay and
then pop up the search thing after the network
call completes, or would we want to just say,
hey, I don't have any articles yet so have fun with that. MATT SULLIVAN: Well, if
you pass in the stream, then you don't necessarily have
to wait because it will still resolve here, right? Because the stream will
eventually start pumping data through at some point. Now, you could wait,
or you could just-- because we're going to have to
read a stream, when you have a stream builder
on this side, it's only really going to start
to resolve when you have data coming through the stream. ANDREW BROGDON: And so this is-- these are behavior
subjects under the hood, which means they have a
value to start with, right? MATT SULLIVAN: It means it
remembers the last value that went in, unless you put
this-- unless you seed it, it won't have a value
at the beginning. But every time you create
a new stream builder, it will immediately pull the
last value from that stream. So I don't think
we're seeding it because we have nothing to seed
unless we seed an empty list. But if we pass in the
stream, we can still do the whole stream plumbing. ANDREW BROGDON: Interesting. OK. So we can pass in this,
and I go down here and say where I said that
before, actually meant stream. Right. MATT SULLIVAN: And one of
the ways that I typically solve this is I
have an Inherited Widget which contains
a stream, and then I can access it anywhere. We're just passing it through
manually at the moment. That's totally fine for
an app of this size. But now that we
have the stream-- ANDREW BROGDON: We could
return a stream builder here. Could we not? MATT SULLIVAN: We
need to return a-- yes, we could. Because it will
take a new widget. ANDREW BROGDON: And so we need
to type our stream builder. We should be getting a stream
of unmodifiable list view article like that. MATT SULLIVAN:
Unmodifiable mouthful. ANDREW BROGDON: Yeah. And-- oh, actually,
that's results. Let's do suggestions first. MATT SULLIVAN: Yes. ANDREW BROGDON: Because
suggestions come first and so I'll return. I'm just inventing the new
name-- new names for widgets right now. That's what I do. Alternative widget names. So what do we need
for a stream builder. And we need a stream
which we can give. That's just our articles. And we need a builder. And so this is one
of the things I like. I don't know if the
S code does this. You get the nice little hover. Because I can
never remember what the signature is for
builders and [INAUDIBLE].. MATT SULLIVAN: Excuse me, but
the S code has hover, as well. ANDREW BROGDON: There you go. MATT SULLIVAN:
Your insinuations. So we're going to start with
the-- the IDE wars, here. ANDREW BROGDON: Yes. I do everything in vi
from the command line. MATT SULLIVAN: There's a
plugin for dot for vim. ANDREW BROGDON: Oh, yeah. MATT SULLIVAN: Next
on The Boring Show. Flutter for-- ANDREW BROGDON: Another
episode that involves me trying to learn to use vim. OK. So we're taking this and
it's an async snapshot. MATT SULLIVAN: And you
kind of want to type this one because it helps the-- ANDREW BROGDON: Snapshots. Still getting yelled at. Oh, because it's
an unmodifiable. MATT SULLIVAN: Cool. ANDREW BROGDON: Here we
go, everything's great. All right. MATT SULLIVAN: So
the [INAUDIBLE] plumbing we're going to need
now is if there's data or not. ANDREW BROGDON: That's right. So let's say if-- and
I'm just going to do-- MATT SULLIVAN: You could
do snapshot, that has-- ANDREW BROGDON: I'm going to
say if it doesn't have data-- has data-- MATT SULLIVAN: I use has
data for FutureBuilder. And I can't remember if
I use stream builder. I usually use the
connection state. ANDREW BROGDON:
For right now, I'm just going to return a
child that says, no data. Like that. Semicolon. And, otherwise, we can return
something that means something. So we could do-- we're going
to need a column of rows, I imagine. MATT SULLIVAN: List view. ANDREW BROGDON: Oh, list view. MATT SULLIVAN:
Because we're going to have an unmodifiable list. The easiest way to
do this, probably, at least to see if
it's working, is to have a list view
of the articles. ANDREW BROGDON: OK. Yeah. That's a list view, children. So we're going to map our
articles to something. MATT SULLIVAN: We
can map them just to the title for the moment. ANDREW BROGDON: Map to widget. So we're going to
take an article and we're going to convert it
to a text with a dot title. MATT SULLIVAN: Do you
want me to text Will and find out what font he
wants us to use for this? ANDREW BROGDON: I feel
bad because he didn't have enough time to finish his work. And like he showed a bunch
of really useful stuff about the API, and
things like that. But like, you know,
his personality, he wanted everything
to be like proper and finished when
he was done with it. And they just didn't have time. MATT SULLIVAN: I can't
wait to see what he thinks of our search implementation. ANDREW BROGDON: OK. So let's save that. No data. MATT SULLIVAN: Yeah. That-- well, result-ish. ANDREW BROGDON: Yeah. That's interesting. OK. So let's-- MATT SULLIVAN: Oh,
maybe because the-- maybe we'll need to
re-- no, that should-- ANDREW BROGDON: Let's just
start this up [INAUDIBLE].. There we go. So we had-- MATT SULLIVAN: So we do
have data now, it's just-- ANDREW BROGDON: We do have data. We just have me forgetting
to put to list on the end of my maps, as I always do. MATT SULLIVAN: Yeah,
I do that, too. ANDREW BROGDON: There we go. So we've got some data. And then we didn't actually--oh,
I am not in the search bar. So there we go. So we're not actually using
a query, which we need to do. MATT SULLIVAN: So-- OK. Do you want to-- should
we start the list, or should we get-- we get the
[INAUDIBLE] working first. ANDREW BROGDON: Yeah. MATT SULLIVAN: It
should be easy. Because all you
want to do, right, is you would just want to
search for a substring. ANDREW BROGDON:
Going to do aware and just do-- yeah,
a straight up. We get for-- MATT SULLIVAN: So what we
do in the list view section, we can filter the
list by using-- I'm presuming Dart
has a substring? ANDREW BROGDON: Yes. MATT SULLIVAN:
We'll work it out. ANDREW BROGDON: Yeah. There's a-- MATT SULLIVAN: Contains. ANDREW BROGDON:
--include container. So I'm sure there's-- the Dart string library's
probably been around for a decade at this point. So it's got to be
in there somewhere. Articles. Where? And then I probably have
to give this a slam dunk. MATT SULLIVAN: I can see
the Dart team talking to us after is going, really,
you don't know the string API. ANDREW BROGDON: After you
talking [INAUDIBLE] material, we'll get a-- we'll get a
target date for the Dart team. So dot title dot-- wait a second. MATT SULLIVAN: Stream
class [INAUDIBLE] library. We have a contains. ANDREW BROGDON: Wait a second. Oh. This is not even
remotely correct. I'm operating on the stream. Snapshot.data. Just like my IQ was not-- title. There we go. Contains, yes. Can we do it to lower here? MATT SULLIVAN: I think you-- ANDREW BROGDON: There we go. Contains. MATT SULLIVAN: Well, contains
actually takes a pattern, so you could do some
pattern on that-- ANDREW BROGDON: Oh, my, here-- MATT SULLIVAN: But I think-- ANDREW BROGDON: Pattern is. MATT SULLIVAN: --we can use
a straight string for this. ANDREW BROGDON:
Can I format that? There we go. That's a little better. MATT SULLIVAN:
Contains query maybe. ANDREW BROGDON: I can't-- that would be-- all right. Hold on. Open source check. Let's drill down. Returns true. If the string contains
a magic other. Other is a pattern. Pattern is an abstract class. MATT SULLIVAN: This
will [INAUDIBLE] a regex or a string, or maybe both. But isn't a string like a--
just an exact match for a regex? Oh, it's been so long since
I've done regular expressions. Welcome to the regular
expression show where we will spend
the next half an hour trying to work out how to
do basic substring magic. ANDREW BROGDON: No kidding. MATT SULLIVAN: Have
we tried to run this? ANDREW BROGDON: Let's
just try it with this and see what happens. MATT SULLIVAN: You
might want to-- I think, navigating back
and forth might reset the-- reset your-- it'll-- cause
it'll kill the stream builder. ANDREW BROGDON: That needs
to be results anyway. Let's just try
hard restart here. So I can do carbon. Yeah, you can, just
give it a string. MATT SULLIVAN: So that works
except for when there's nothing there. ANDREW BROGDON: Yeah. Thanks, dark courting. MATT SULLIVAN: We'll reach
your APIs better the next time. ANDREW BROGDON: We promise. So that gives us some results. We still need to do something
better than this ugliness. So let's do something nice,
or we could make a little-- MATT SULLIVAN: We
could make a list tile. ANDREW BROGDON: Let's
make a little-- yeah, let's make a little stateless. MATT SULLIVAN: I always
end up making less tiles. Because, apparently, you know-- ANDREW BROGDON: Here is one. You're right, we
got a list view. We could make list tiles. That was a good point. So we're going to map
to list tile like that. What do I put in here? MATT SULLIVAN: Title. ANDREW BROGDON: Title. Well, that's easy, title. Oh, no, messed it up. Need my a dot-- here we go. MATT SULLIVAN: What else do
we have in the article class? ANDREW BROGDON: Oh, it
needs to be a widget. Text. Easy peasy. We could put a
leading icon on it. Like an article. MATT SULLIVAN: Book. Bookmark. ANDREW BROGDON: Book. Bookmark border. MATT SULLIVAN: You know
what else you can do you? You can put the substring as
the URL if you're feeling-- ANDREW BROGDON: Oh, subtitle. Here we go, yeah. Text, I'm guessing. a.url. Whoa. MATT SULLIVAN: Why is it
not showing the title? ANDREW BROGDON: This is a-- I think it's because we've-- there's been some heavy
modification of the-- I'm guessing this
title is just an-- this URL is utterly
enormous, and maybe we don't want to show it. So let me do this first. MATT SULLIVAN: Yeah,
let's take out subtitles, see what happens. ANDREW BROGDON: So that
gets us-- that's better. But those are still-- you want to give them-- well, if that's the
body text, then I really just need to do this. MATT SULLIVAN: But that's odd
because like title should-- it auto styles it
for list title. ANDREW BROGDON: Open source. So let's see, we got a build
method in here somewhere, right? Divide tiles. Oh, my goodness. List tile's doing
a lot of stuff. Title text is title style. MATT SULLIVAN: Yeah, so
that should be much bigger. I'm surprised how small that is. ANDREW BROGDON: Which is using-- oh, it depends on
your list tile. Style. So if this is body two,
that would look a lot like a body text font. MATT SULLIVAN: OK. So it's pulling from this style. ANDREW BROGDON: All right. So let's go back. MATT SULLIVAN: We
could retheme it. ANDREW BROGDON: And
let me take that off. Say isn't-- I know for a fact
you should be able to jam this in here. Right. That should work. And be huge and not-- it's done incorrectly. OK. Interesting. MATT SULLIVAN: We could
just give it a font size. Might be-- ANDREW BROGDON: Style. Good old copy width. Font size. 10.0. How does that work? 16.0. There we go. MATT SULLIVAN: OK. ANDREW BROGDON: Again,
apologies to Will. I'm sure there's a
better way to do this. Format on my code. Take out our subtitle here. MATT SULLIVAN:
Because you could do-- with subtitle you can just
say text one line and end with an ellipsis, that
way then it doesn't-- it doesn't overflow everywhere. But it's good enough. ANDREW BROGDON: OK. So now part of the issue
here is that these are-- these are suggestions. These aren't even the actual
results, which is interesting. So what's the difference
between suggestions and results? MATT SULLIVAN: Transition
from showing results by build results to suggestions
from build [INAUDIBLE].. ANDREW BROGDON: After the
user submits a search-- so is this going to be
the same thing almost? MATT SULLIVAN: Well,
notice that as you type, it's showing the suggestions. What happens if you hit Return? Does it then show a
different set of results? Because suggestions don't have
to be a filter of the list, they could be anything. ANDREW BROGDON: That's true. MATT SULLIVAN: So if we-- ANDREW BROGDON: Yeah,
because technically you're suggesting things that
could go into the query. MATT SULLIVAN: So it doesn't
have to be built off that. If we hit-- because, usually,
when the keyboard pops up, there'll be a search key. ANDREW BROGDON:
Suggestions should be based on the current query string. If the query string
is empty, it's good practice to show suggested
queries based on past queries, or the current context. Query. OK. So when list tile
on tap is called, query should be updated with
the corresponding suggestion. And the results page should be
shown by calling show results. So what we're
supposed to be doing-- MATT SULLIVAN: Oh, but
that shows the results. That's different
to build results. ANDREW BROGDON: So we
should be putting a-- MATT SULLIVAN: How could
we trigger build results? ANDREW BROGDON: On tap. Should be query equals-- this is here. We could do it like that. Why are you yelling at me? What did I just forget? MATT SULLIVAN: You're
missing the brackets on tap. Open and close brackets. You forgot those. ANDREW BROGDON: We
could do it like that. Let's save that up. That worked. Interesting that it just
eliminated our preview. That's interesting. OK. MATT SULLIVAN: Well,
that's going to re-- that's going to rewrite
the query, which is then going to filter everything out. So the question is how do we
get build results to trigger? If you type something
in and hit Return? There you go. So that's building the results. So that's the equivalent
of hitting the Search icon on the keyboard. ANDREW BROGDON: So
let's take out-- MATT SULLIVAN: Because
what you want to do-- ANDREW BROGDON: Let's take
out the icon on this one. And do it like that. So these actually look
like suggestions now. I'm a little weird-- weirded out
by the fact that should leave us with one thing in here. If we just put this-- MATT SULLIVAN: But, no, because
that's now running your-- that's now building
your container, because you've-- there's
no longer a suggestion. It should be
showing the results. See what I mean? ANDREW BROGDON: All right. Let's build some results then. So we would do the
same basic thing here. We'd still have a
stream builder, I guess. So we do a live update of
your search query for you. And-- MATT SULLIVAN: So I guess-- ANDREW BROGDON: --we're
bloating the code. We can clean this
up if we have time. And here we could
put the icon back in. And you know what, I'm
going to give these a color. Blue. Just so we can tell them apart. Do that up. We'll go back up here
and say, OK, that's it. Now, I can put our icon back. So we'll be able to
tell these apart. And then this will have
it on tap that actually closes with the article. Because if you had a
result, then you're done, you want to close
the search down. Or we could do-- MATT SULLIVAN: Or we could
navigate to the article directly. ANDREW BROGDON: Would
we want to do that back on the original screen? Because we have to close the
search at some point, right? MATT SULLIVAN: Well, we
can do the URL launch, and then we can still call
the navigate.offpop after it, potentially. I'm not sure how
that would interact, because the URL
launcher is no wait. We can play around
with it, see-- ANDREW BROGDON: OK. Yeah. And, actually, we've been
going for a little while now. Do you want to-- we got some questions we're
going to answer, and give you a chance to do some coding-- MATT SULLIVAN: Well, let's-- ANDREW BROGDON:
--and finish this up. You just want to see if we-- MATT SULLIVAN: Let's see--
let's see where we got to, because you've got like Blue
code and icons and all sorts of other things. ANDREW BROGDON: You
don't want to-- you don't want to take over a
project in a really weird state in like a few minutes? That's weirding me out. So I can type in that. OK. That gets me a results. And that closes OK. MATT SULLIVAN: I think it's
because your har-- you're overwriting the URL. It's getting very
weirded out, as opposed to just saying search. Because if you tap
in it, it's not supposed to take
you to the results because you're selecting it. And that should, actually,
launch the article, if you see what I mean. ANDREW BROGDON: OK. We can-- I mean, we
could close doing-- how do I close here, as well? MATT SULLIVAN: Yeah,
because the on tap there is going to say I'm
choosing this result as opposed to show it me again
in the search result. ANDREW BROGDON: I can
certainly do that. MATT SULLIVAN: So
you can choose one. It goes back. Or you can search and click
it and it also goes back. Of course, we're
going to-- yeah, OK. ANDREW BROGDON: All right. So let's-- why don't
we do some questions. Yes. Questions. And just a reminder,
if you're watching, you can post questions
for us and, you know, we'll try to answer as
many as we can on the show. You can post YouTube
comments right on this video. You can, also, as you can
see from our whiteboard, you can use the hashtag
Boring Show, Twitter hashtag and tweet them at us. We check those out
whenever we can. And I have two for today. So one of them comes
from Connor Aldridge. This is about a week
ago-- week or two ago. And, it says, "I'm
really curious about how you could remove
the top gray status bar with the white background,
because that both looks better and is what Google does." This is in one of
our other videos they were asking about the-- Connor was asking about
the notification status bar at the top of one of the apps,
which a lot of apps get rid of. They sort of hide it away. And so Flutter does have a
mechanism for doing that. You can customize it and
do some other things. Let me pull up-- I have done it. When I was teaching
myself Flutter, I made a little reverse game. And it has a game
UI so I didn't want to have the status bar,
or the navigation bar, at the top or bottom. And I also wanted to
make sure that people didn't flip the device. So it was just a
simple example, and I didn't want to have
to deal with having two different layouts for it. Because I was but a
wee newb at the time. And so there is a way
to interact with what they call system Chrome. There's a library for
it in Flutter/services, and it offers things like
setting your preferred orientation. So if you want to lock
your screen in portrait, or landscape, if you
want to definitely enable the navigation-- or the
navigation or notification areas, or definitely
disable them and hide them away until the user taps
manually to bring them down, you can do that. And you just make simple
calls into various methods. So the system Chrome class. Here we go. It's got a bunch
of stuff in here. Preferred orientations,
you just give it a list of the orientations you want. And enabled system
UI overlays, you give it a list of the
overlays you want, or an empty list
to hide everything. MATT SULLIVAN: So then you
just give it a scaffold. You don't give it an app bar and
that gives you your full page for handling material-- ANDREW BROGDON: I can still-- I can still have
the app bar, it's that very top layer
where you have like your battery and your-- you know, your Snapchat-- MATT SULLIVAN: Oh,
so that [INAUDIBLE] all of those as well? ANDREW BROGDON: --and
those little icons. That hides those
away and gives you that nice, clean full screen
interface that a lot of apps really like. MATT SULLIVAN: You still
need to take into account-- you still need your safe
area for notch devices. ANDREW BROGDON: That's true. MATT SULLIVAN: OK. Safe area is great if
you do go full screen for pixel 3s and the iPhone
Xs of this world, that will make sure you don't have
to manually pad for those areas. ANDREW BROGDON: It'll
do a media query on your behalf, helps
with rounded corners, notches, stuff
like that, which is why we made it the very
first ever widget of the week way back when. So that was one question. I thought it was really-- a
really good thing to cover. Another one was from
someone named Jim Morrison. MATT SULLIVAN: The
Lizard King asks-- ANDREW BROGDON: Yes, I don't-- I don't know. Fun fact. He and I actually went
to the same university. MATT SULLIVAN: This
one or the other one? ANDREW BROGDON: The
Lizard King, Jim Morrison. MATT SULLIVAN: OK. Right. Sorry about that. ANDREW BROGDON: Yeah. And, he said-- this
is actually a concern. He says, "One thing that
bothers me about Flutter is that it seems to allow coders
to easily slip into writing massively indented code." And Flutter is a fairly
unopinionated SDK. You can sort of write
it the way you want to. And so this is actually
a very good thing to be thinking about,
especially if you're going to be a team lead or
something like that where you really need to set policies
for other coders to follow, maybe beginners who don't
have as much experience. And so I wanted to real
quick highlight yet-- yet again Brian Egan's
wonderful architectural samples, where I think he does a
very good job of this. I think the best way to
combat this sort of thing is to lead by example. And so if you're a
team lead and you can show your people exactly
how to separate things, like business logic
from UI logic, you can go a long way to
dealing with that concern. And I think Brian
Egan here, he has-- if you look at his
project structure, he has a presentation folder
with all of his presentation level-- presentation level
widgets, which are just delightfully simple. They're very
simple-minded widgets. They just take basic
properties and convert those into onscreen presentation. And if you go into
his containers folder, now, you start to
see things that are using business logic to
create those presentation level widgets. And so as I've-- and, again, I've
pointed a zillion people to these examples. If you would like to see some
very well architected Flutter code that shows how to deal
with those sorts of concerns, I highly recommend these. You can find them in our samples
index at Flutter/samples. We have a curated
index of samples. And you can also just, you
know, throw it into search and do Flutter
architectural samples. You will-- you'll
find these suckers. MATT SULLIVAN: And
a rule of thumb is if your own widget
implementations start to massively indent or
grow by number of pages, decompose them into
individual widgets. In the long run, it
will help reusability but, more importantly,
it will help readability. And the age old use async and
await in futures versus dot then, and that will
also help with when you start to play around with
a lot of asynchronous code, ending up in that pyramid of-- ANDREW BROGDON: The right
word drift as it is called. MATT SULLIVAN: Oh,
back we go again. ANDREW BROGDON: Which
has been mentioned in some of my own pull requests,
to be completely honest. I think Jonah
pointed it out once. Yeah. All right. You want to switch and
we can finish this up? MATT SULLIVAN: All right. Let's quickly see if we
can get some URLs logic. ANDREW BROGDON: Yeah,
let's do that last little-- put a bow on it
and call it a day. All right. I'll just log in and check your
email here while I'm at it. MATT SULLIVAN:
Which idea is this? OK. Right. OK. What have you left me? ANDREW BROGDON: I think we just
need that last little piece of whether-- where we're going
to watch the URL, and where we're
going to launch it. MATT SULLIVAN: So this
is working well so-- I mean, people, you know,
there is a lot of overlap here between the suggestion
and the actual result. But in many search cases, you're
not doing direct text search, you're doing much more
contextual based search. So-- whereas, we do
have overlap here. Now, what we could
do is we could-- let's take a look at-- now, I have to get
used to your PC. Where is-- OK. Here we go. Show search. Back again. No, no. Yes. Here we go. So we have build suggestions. And we have the
search delegate class. Now, what does it say
about returning results? ANDREW BROGDON: So that's
what close does, right? MATT SULLIVAN: So
close returns a result. And if we look at
the implementation, that's hopping the results. ANDREW BROGDON: That's
using the navigator and it's popping with
the result, which is then caught by show search, right? MATT SULLIVAN: Yes. So, basically, that
means that show search is returning a future
of type article, which means we go back to-- it's not [INAUDIBLE]. I was confused even by that. Now, why is that red? ANDREW BROGDON: Oh,
it's in navigate repo so we can push this
when we're done. MATT SULLIVAN: So
what we need to do is we need to go back to-- no. Oh, main dot Dart. Hang on. Overall the same one. I would definitely break this
into multiple [INAUDIBLE].. ANDREW BROGDON: It's still
a very small app considering how much hacking we've done on
it, which I find fascinating. MATT SULLIVAN: That's very true. On the next episode, Will
will style our search page. Because as soon as
he watches this-- so where is our search. Show search is here. So what we're going to do is-- how are we going to do this? So this is going to
return to future. So we could do on
pressed, we would have-- remember when I said
don't use dot then? ANDREW BROGDON: Well, you can-- I mean, on press can be async. You can throw an-- you can
throw an async on there if you'd prefer to do that. MATT SULLIVAN: So I
could do that, right? And then I can do this, right? And then I can do
final result is this, and this is going to be-- well, I could
technically do file-- ANDREW BROGDON: Yeah,
it's interesting because show search does
not have a type on it. MATT SULLIVAN: But we have
typed it from the delegate. ANDREW BROGDON: So does it
inherits the delegate there. OK. Interesting. MATT SULLIVAN: So it's
inheriting it from this. ANDREW BROGDON: So even if
you didn't put article result. MATT SULLIVAN: Yeah, because-- I think we can-- OK. I think Dart's smart
enough to work that out. And I'm not just trying
to make friends again with the Dart team
after our miserable attempt at looking up string. ANDREW BROGDON:
Sometimes you just try whatever would make sense,
and it probably works. MATT SULLIVAN: We
could just do print. Where are we? Oh, it was going to be-- I was going to-- I was going to do snack
bar, but we're in scaffold and, you know-- ANDREW BROGDON: Yeah. Well, you could just
throw a builder in there. MATT SULLIVAN: Fine. I'll do it properly. Fine. I'll do it properly. ANDREW BROGDON: We're
going to launch URL anyway. MATT SULLIVAN: So the
reason why I can't do that-- I'll do what I
thought I was going to do just so we can see why
[INAUDIBLE] dot show snack bar. Snack bar. And if Emily Fortuna
is here, we'd call this admiral
snack bar because-- ANDREW BROGDON: Because
she's funnier than us. MATT SULLIVAN: Yes. And it's funnier
when she says it. Snack bar takes content. Spot the person who's written
a shitload of snack bars. Why are you not-- ANDREW BROGDON: I think
it's snack capital B bar. MATT SULLIVAN: And then we would
do text and do results.title. Why not? Does that look right? Let's put some commas in. ANDREW BROGDON: So it's
alt command L to format. MATT SULLIVAN: Alt. ANDREW BROGDON: Or option
and command L to use. There you go. MATT SULLIVAN: Thank you. You learn something
new every single day. So this is not going to work. And the reason this
isn't going to work is because we're trying
to get the context-- we're trying to get
scaffold out of the context, but it hasn't been built yet. And this used to mess me up all
the time, and I'd pull it out. And the easiest
way to get around this, as Andrew
pointed out, would be-- how do I wrap with widget? ANDREW BROGDON: Option enter. MATT SULLIVAN: This is what
happens when you let me drive. You can put a builder in. And our builder is
going to have a builder. And then we're going
to put in a context. And then we're going to
put in a double arrow. OK. So what does this look like? So if we go back and we do
search and click on this. Now, I'm not
surprised that work. It's always going
to work first time. ANDREW BROGDON: So
real-- real quick, just to make sure that we're
being clear about what-- why we put this builder in here. MATT SULLIVAN: Yes. ANDREW BROGDON: So when
you tell it scaffold of, and you give it a
context, it goes, OK, I'm going to go from
here up, and I'm going to look for a scaffold. MATT SULLIVAN: It's going to
look up the widget hierarchy tree, but the problem here
is when we called this, we haven't actually
built scaffold yet, or it's not
necessarily in context. So if I remove this option-- what is that, return? ANDREW BROGDON: Alt
option enter, yeah. MATT SULLIVAN: Option enter. So if I remove widget,
where should we move widget? ANDREW BROGDON: I don't know. MATT SULLIVAN: [INAUDIBLE]. If you were to remove
this, this would actually throw a runtime error. ANDREW BROGDON:
Because it wouldn't be able to find the scaffold. MATT SULLIVAN: Exactly. ANDREW BROGDON: Right. MATT SULLIVAN: So the
thing is that if you use scaffold it of in
the same build function that you're defining
the scaffold, you will hit problems. And it's the same with
whenever you use dot off. So the easiest way instead
of having to break things up to multiple build
functions is to wrap it in a builder, which gives
you a separate build context to measure. I've explained that badly. So let's see if this also works. If I search-- ANDREW BROGDON: I
think you're still-- I've done that a
time or two, as well. MATT SULLIVAN: If I search
for Neil Armstrong-- oh, dear, I've-- ANDREW BROGDON: Did
we-- oh, you're broke. You're at breakpoint. MATT SULLIVAN: I broked. ANDREW BROGDON: Exception. OK. What is going on? MATT SULLIVAN: I don't know,
let's just continue there. OK. So let's search for Neil. Neil's gone. Neil is there. Oh, because you're
lower casing it. ANDREW BROGDON: And I
didn't lower case the query. MATT SULLIVAN: Lower
case the query. ANDREW BROGDON: Where's my-- where's my cone of shame? MATT SULLIVAN: Well, we'll
fix that in a minute. So if we hit Return, we get
the thing, we click the thing, we get the snack bar. ANDREW BROGDON: Right. MATT SULLIVAN: So
let's take this to its foregone conclusion. That sounds very ominous. We leave that there
for the time being. But do we have your
launcher in here already? ANDREW BROGDON: Yes. Because that's what
that icon is doing. And so we can probably-- MATT SULLIVAN: Wrapper
function for that. URL. ANDREW BROGDON: There it is. Yeah, if await,
can launch article. Launch article. So you could probably
take that exact thing out. Yeah. MATT SULLIVAN: And
we'll go back up. Probably wouldn't
ordinarily break this into a separate function. If await can launch,
and this is going to be result. [INAUDIBLE]
article, result. Snack bar's kind of redundant at this point. But let's just see what happens. ANDREW BROGDON: Everybody
likes a nice snack bar. MATT SULLIVAN: You
can choose this. ANDREW BROGDON: You might
have already built this. You've already built
this section of it, so you might need
to do a hot reload-- or a hot restart. I don't know. MATT SULLIVAN: OK. Where is my hot
restart button here? Oh, wait, this seems to have-- OK. I'm going to restart the app. I have no idea what those mean. ANDREW BROGDON:
Those are the things that teach me the key commands. MATT SULLIVAN: And I'm
going to comma this out because redundant. And we did the [INAUDIBLE]. So there should be no reason
why I can't launch this here. So let's see where
we get to here. So we get here and
we type carbon. And then we click. ANDREW BROGDON:
And there it goes. MATT SULLIVAN: So it
was a little janky 'cause we're also pushing
back, and whatnot, I mean, there are
several ways around that. We could-- so we
go back and then we show-- what we could do
is we could launch from here. So what we could do, for
example, is we could-- and let's see if I could
do this real quick. And I'm going to take
this before you tell me this is a terrible idea. ANDREW BROGDON: No, I'm
going to tell you we've been going for almost an hour. MATT SULLIVAN: OK. Let's see if we can
quickly get this done. As people frantically
waive at me-- waive at me. ANDREW BROGDON: I don't
think URL launch is important to this. No, we're still
in the same file. That should be fine. Result doesn't exist. There we go. MATT SULLIVAN: And then we go
back and we choose another one. Oh, this is coming from results. So I'm going to go here. Isn't this riveting
watching you work up. ANDREW BROGDON: There you go. MATT SULLIVAN: OK. Little bit of work there just
in terms of what happens when. But we've gone from having-- ANDREW BROGDON: No
search whatsoever to-- MATT SULLIVAN: To
having kind of cool-- I think it's pretty neat. ANDREW BROGDON: Yeah. All right. MATT SULLIVAN: And you
can type up your code now that I've got it out for-- ANDREW BROGDON: Before
I push it up to you. MATT SULLIVAN: --over it. Yeah. ANDREW BROGDON: All right. So I guess that is today. Hopefully, you've enjoyed
watching us knock out some search for this. It's a fairly simple API,
you know, you just get-- one call to launch it
and there are four calls to return the widgets
that you need to present the UI for searching. So, yeah. Again, please send
us some questions on the comments for this
video, or you can tweet us with the hashtag Boring Show. We always check those out. And we try to respond to your
questions both, you know, in the comments and
here on the show. But, yeah, we'll
see you next time. MATT SULLIVAN:
Thank you very much.