April 2, 2020
Custom Drawer, Filing Bugs, Working with Databases (The Boring Flutter Development Show, Ep. 27)

Custom Drawer, Filing Bugs, Working with Databases (The Boring Flutter Development Show, Ep. 27)

and welcome back to “The Boring Show.” I’m Emily Fortuna. EMILY SHAK: And I’m Emily Shak. EMILY FORTUNA: Welcome. So yes, you may have
seen Emily on stage with me at Google I/O
a couple of times now. EMILY SHAK: I think
it’s been three. [LAUGHTER] EMILY FORTUNA: And I’m super
glad that you could join us on “The Boring Show” as well. EMILY SHAK: Yeah. Thank you for having me. I’m excited to be here. EMILY FORTUNA: So
when we last stopped, Andrew and I were working on
adding a database so that we could favorite articles. And we sort of had that working. We were running into some issue
where the UI wasn’t always getting updated with the
stories that we were adding, but it seemed like
our database was. So the mystery continues. We get to dig into
what’s going on. First of all, I was thinking
about this a little bit. And I think there may be
an issue with the stream that we wrote. So if we go over to
our Favorites file, we have this we have
our class with– where we can query the database. And if in our “is favorite,”
we are investigating, in our table, trying
to select a favorite– an entry in our favorites
table, and watch it. And I’m wondering if
there is an issue with– if our favorite doesn’t
exist in that table, maybe it’s trying to query
it, seeing there’s nothing, watching on that forever,
and then we’re filtering. And if there’s like– if
we’re watching on nothing, maybe it doesn’t fire. EMILY SHAK: So does this work
if you were to rewrite it such that we’re just
watching the full table, and then updating based on
that, rather than just watching a single row in that table? EMILY FORTUNA: We should try. EMILY SHAK: Let’s see. EMILY FORTUNA: So yeah,
let’s test that out. So let’s see, we want to
select the whole table. Launch. And then, from that,
we want to just filter where our favorite is
the ID that we want. So watch.where. I think we should just
be able to do that. And then we convert that list to
test if there is at least one. It should be only one, but– oh, map it. Favorite.ID. What is it not happy about? EMILY SHAK: So I
think favorite here would be the full table,
rather than the individual– EMILY FORTUNA: Oh, right. EMILY SHAK: –item. EMILY FORTUNA: OK, so let’s
call this favorites list. Favorites list. All right. So we want to actually
say, in that list– yeah, OK. So how about a– sorry, you were saying? EMILY SHAK: Do you think we
should map here, and then– EMILY FORTUNA: Yes. EMILY SHAK: –map that
list to any entries that might match our query? EMILY FORTUNA:
Favoriteslist dot– don’t we want to actually, from
that list, inspect it, right? Inspect within the list. EMILY SHAK: Mhm. EMILY FORTUNA: So yeah, OK. Map works. Map. And then, inside
that list, we want to say where
favorite.ID equals ID? And then– EMILY SHAK: Are you
missing a paren at the end? EMILY FORTUNA: Yes. EMILY SHAK: I get to be the
one who sits here and just scrutinizes all of the code. EMILY FORTUNA: Works out. EMILY SHAK: Yeah. EMILY FORTUNA: OK, so we have– so we’ll get rid of– well,
let’s just comment this up for– And I think– yeah, filter
from that and just– is there any– are there
any that have that? EMILY SHAK: Yeah. If feel like we could simplify. EMILY FORTUNA: Yeah,
that’s kind of wacky. EMILY SHAK: We got two maps. EMILY FORTUNA: OK. But– EMILY SHAK: I mean,
it should work, right? EMILY FORTUNA: Yeah. EMILY SHAK: We can at least
use this to test if it works. EMILY FORTUNA: Sure. What if– let’s see, what would
be the better way to do this? It would be to– there’s a filter? OK. EMILY SHAK: Can we just check,
at the end of the where call, if the length is greater than 1? Do we need that last map? EMILY FORTUNA: Let’s see. Where– that should
return a list– yes, correct. So that dot length. And then yeah, get rid of this. Oops. [SCOFFS] EMILY SHAK: Happens more
often than I’d like to admit. [LAUGHTER] The selecting and moving
to a different part. EMILY FORTUNA: OK, so yes. That looks a little better. So we’re taking– we’re
watching the entire table, getting the list of all
the entries in that table, filtering to find the ID, and
then, from that resulting list, it should be only one. We have greater than 1. Whatever. Greater than or equal to 1. Yeah, OK. So let’s test this to– I’m going to do a
hot restart just because this is a standalone–
this is not Flutter. It’s like your dart. So it wouldn’t run
the build method. OK. So now the moment of truth here. All right, all right. EMILY SHAK: It seems reasonable. EMILY FORTUNA: Yes. EMILY SHAK: Does that
get around the issue you were seeing before? EMILY FORTUNA: Yes. So let’s stick this
stream builder back in the expansion title,
where we had originally intended it to be, rather
than this weirdo thing above. And just for grins– oh, my gosh. OK, and I guess–
so the moment– the real way to test
this is we need to– let’s stop it and
pull it up again. Because it should
persist across runs. That’s the whole point of
this database business. So we will pull it up again. So I think the question, for
me, is I thought with Moor, I should be able to– we should to look and see
if that’s expected behavior. Because I thought that it
should behave this way. And if not, then we
should file a bug. EMILY SHAK: Yeah,
let me go ahead and look at the Moor plugin. EMILY FORTUNA: OK, yeah,
while it’s building. EMILY SHAK: Is it this one? EMILY FORTUNA: Yes. EMILY SHAK: All right. Let’s just take a look here. EMILY FORTUNA: And the
good news is it does– we are seeing those persists. So we’d just
written query wrong. Or actually, I think
that query should work. We’ll look at the docs. EMILY SHAK: Yeah. So I think– so this
seems to correspond to what we’re doing now, which
is looking at the whole table, I think. EMILY FORTUNA: There was another
page that has full docu– oh, scroll up for a second. Check out the documentation
for a more detailed guide. EMILY SHAK: Sure. EMILY FORTUNA: Writing queries. EMILY SHAK: All right. EMILY FORTUNA: Let’s see. Select blah ware watch. EMILY SHAK: So this
one looks like we’re watching an individual row,
like you were doing before. EMILY FORTUNA: Yeah. EMILY SHAK: So that’s
supposed to work. EMILY FORTUNA: Yeah, so
I think the one other way I can test this is– or check this is they have– I downloaded the repo, and
I can look in their tests. Yeah, so if I look
in streams test, I just want to see how
they wrote their tests to see if it’s like– EMILY SHAK: Yeah. If there’s a test
for that particular– EMILY FORTUNA: Right, yeah. EMILY SHAK: –watching
one line in the table. EMILY FORTUNA: Or
anything to indicate, this is not supported
or whatever. OK, so fetch when the
first listener attaches. Or just selecting looks
like on [INAUDIBLE].. So that’s like the table. This is the table, table. Or wait, look first. Yeah. Their tests are not amazing. They only test on the table. So OK, let us– we’ll file a bug. And either they can tell us,
no, you’re using it wrong. EMILY SHAK: Yeah, it could
be that they don’t intend to support this,
and just might want to be a little more clear
about this documentation. EMILY FORTUNA: Yeah. Yeah, when I read it– because
it literally says it will– it will automatically– whenever
the underlying data changes. Which to me says, like,
anything in the table, but maybe I was wrong. So let’s file a bug. Do you want to do
it on your computer? EMILY SHAK: Sure. All right. EMILY FORTUNA: So scroll up. There’s the repository
link on the About section. Above. EMILY SHAK: Oh, here? EMILY FORTUNA: Yeah. Click on that. EMILY SHAK: All right. EMILY FORTUNA: And Issues. EMILY SHAK: Yeah. I wonder if they
already have one, or if we need to add a new one. EMILY FORTUNA: Improve code ish. Unless– yeah, let’s
look at that one. Only tests– EMILY SHAK: No. EMILY FORTUNA: Exactly
what we were commenting on. Your coverage could be better. EMILY SHAK: No, they’re just
talking about in general. Like, how do we know what
our coverage is, I think. EMILY FORTUNA: Oh. EMILY SHAK: Rather than– EMILY FORTUNA: Oh. Oh, interesting. EMILY SHAK: Oh, but this
does kind of indicate there are tests elsewhere. EMILY FORTUNA: Mm. OK. EMILY SHAK: Is there any
other directory with– EMILY FORTUNA: Let’s see. Tests. Oh, see, now, what I am doing? Select test. There’s two– EMILY SHAK: This
feature is actually something that would be super
useful for me in my day job. [LAUGHTER] I would love if we
could do this also. EMILY FORTUNA: Oh, nice. Let’s see. OK, yeah, there’s more Flutter,
more generator, and Moor. Let’s see if they’re
testing those. Moor Flutter. Oops. I can totally type. There’s no tests
in Moor Flutter. EMILY SHAK: Meanwhile, I’m
going to start filing an issue, just in case we do need it. EMILY FORTUNA: Thanks. Oh, there is a Moor title. I’ll look in there. Multitasking for the win. They’re not testing that
thing in their other tests. So I think we should– we can safely do it. EMILY SHAK: All right. So what should I say here? I said, “watching
a subset of a table doesn’t reliably
update with results.” Is that– EMILY FORTUNA: I wonder– EMILY SHAK: –accurate? EMILY FORTUNA: Yes, but I
wonder if the issue is– I could be wrong, but my
supposition on what’s happening is like, if we watch
for a line that’s not– a row in the database that’s not
there, that’s my guess of what the problem is. Let me– EMILY SHAK: And then when
it updates, it doesn’t update the query, it just– EMILY FORTUNA: Right. Because there’s nothing there. EMILY SHAK: It ran the
selection once to find, this is the section
that we’re looking at, and then didn’t see any
section, so it’s not updating? EMILY FORTUNA: Right. That’s my guess. Let me test that
a little bit more. Ha-ha-ha. Moor. And then we can– but I
would say keep typing that. EMILY SHAK: Yeah. EMILY FORTUNA: Do you want
me to send you this query? Or you have the
query because it’s– EMILY SHAK: Do I
have the new one? EMILY FORTUNA: –in the repo. No, but you have the old one– EMILY SHAK: Oh, the old one. EMILY FORTUNA: –which
is the one that we need. EMILY SHAK: Yeah. EMILY FORTUNA: And I mean,
yeah, you probably don’t need to copy that
query literally, but use it to say
what we’re doing. OK, so while you
do that, I am going to test my theory that
this thing is only run. So hot restart. EMILY SHAK: Got some markdown
code blocking in here. EMILY FORTUNA: Excellent. EMILY SHAK: Yeah, fancy. EMILY FORTUNA:
People love it when their bug reports are readable. [LAUGHTER] EMILY SHAK: And when
the people filing them have gone through
the necessary steps to determine that it is a bug. EMILY FORTUNA: Oh, true. Yeah. This is also, I
would like to say, I hope best practices
for bug filing. Sometimes, in my history of
working with open source, I’ve gotten things where
it’s like, blah doesn’t work. And you’re like, OK, but– EMILY SHAK: Yeah, we’re going
to try and give as much context for what we were doing
and what we expected. EMILY FORTUNA: Yeah, yeah. So if you can say how you
got into that situation, what happened, what you
think should happen– and so sometimes, bug reports
can take a little bit. But the more information
you get, the better. But also, I will say I know– I’ve talked to Eric Sidel
about reporting bugs in the Flutter repo. And sometimes, I’ve encountered
things where I’m like, this isn’t reproducible. So I don’t know
how to file a bug. And he’s like, file it
anyway because if we have a record of something
happening, then if something similar
happens, maybe we can put those two
together and be like, this is a trend, as
opposed to like– so if you see something weird,
err on the side of filing it. But the more information you
provide, obviously, the better. EMILY SHAK: And of
course, be polite. EMILY FORTUNA: Yes, absolutely. Because we are providing
free software for you. [LAUGHTER] Anyway– EMILY SHAK: We love
when you send bugs. EMILY FORTUNA: Yes. [LAUGHTER] OK, so my theory. I will print out whether this is
really rerunning to check that. So yeah, just to
be clear about what I’m doing here to test this. If it’s the case that the query
isn’t behaving the way you expect it to, it won’t refire. So I’m just putting a
print statement to check if it’s– if it refires,
the builder will run. Yes. I should– I think
that should work. So I hit this. Of course, now it
works as I expect. EMILY SHAK: Oh, does it? EMILY FORTUNA: Well,
I’m going to do– EMILY SHAK: Are we finding
out this isn’t a bug at all? EMILY FORTUNA: I’m going
to do a full restart just because I don’t really. I’m not sure how hot restart
works outside the context of Flutter code. I thought it just
reran everything. But if it’s working,
I’m like, I don’t know. So I’m just rerunning from the– EMILY SHAK: Yeah. EMILY FORTUNA: –from the
get-go just to be extra– EMILY SHAK: I would expect
hot restart would work. Hot reload, I
wouldn’t necessarily, depending on the context. EMILY FORTUNA: But now it works. That’s why I was like,
why didn’t it work before? EMILY SHAK: All right. So are we supposed
to be seeing– EMILY FORTUNA: OK, there. So I pressed this. It didn’t do anything. It’s causing inception because
it can’t– it’s a unique key. It got added to– you can see it– let’s see. Minnesota. Oh, my gosh. I need to clear our
little favorite things. It’s hard to read. Favorites. Yeah, so we tried to add it. It’s already in there. But our UI didn’t update and
we didn’t see that rebuilding thing, which suggests
the query isn’t functioning as we expect it to. So yeah. We’ll write it. They can say that’s not
an intended use case, or I’ll fix that. In either case, this
is a cool plugin. We just want– EMILY SHAK: Oh, yeah, for sure. EMILY FORTUNA: –it
to work correctly, or as awesomely as possible. EMILY SHAK: Thank you
for contributing plugins to our open source ecosystem. EMILY FORTUNA: You bet. You bet. EMILY SHAK: We
really appreciate it. “However, as far as I
can tell, the database is updating, but
it’s not causing”– I want to write– I want to make sure
that it’s clear that it’s not that
we’ve written the UI part wrong without
providing too much context. EMILY FORTUNA: Right. So I think you should say, we
suspect it’s because this– there’s no favorite with
that ID to start with. And oh, here’s another way
to check that, actually. So do I have– let me kill this
again and restart. But I think another
way to test this is now that I have some favorites
in there that are– and I’ll see if I
can remove them. And if that’s the case–
so I tested the adding one, and it was like the
UI didn’t update. But if I can remove
it successfully, then that again suggests that– EMILY SHAK: OK. EMILY FORTUNA: That it’s that
starting query, or starting WHERE clause, the watcher that’s
not behaving as we expect. Of course– OK, so
we got this one. OK, so it successfully updated– yeah. Yeah, if it starts there– EMILY SHAK: OK, so I’m
going to write this a little differently. “However, for my use case,
the entry in watching might not exist before
you make the first update. The behavior I’m seeing is that
when I make that first update and add it to the channel,
my UI does not rebuild. Then, on all
subsequent updates”– well, do I have
to restart the app before the subsequent
updates will work? Does it have to
have started with– EMILY FORTUNA: No, but it
needs to rebuild in some way. So a way to rebuild is if I
scroll down and scroll up, it scrolls in– or if I go to
new stories and come back– that’s interesting. EMILY SHAK: Cool, cool. [LAUGHTER] EMILY FORTUNA: Hold out
for the next bug report. [LAUGHTER] So there’s– our theory
isn’t quite perfect. But maybe we can describe what
we’re seeing and hopefully– so wait. Let me check my print out. I’m printing out
the entire table, so we should be able to
see what’s actually there. Is that– oh, did I delete? I think it’s still could
be what’s going on. Because– or wait, no. OK, we’re going to
describe it as it is. There’s something else going on. It seems to sporadically fire
when you watch on a single row, and I’m not quite sure– but this is a clear case. There’s a little more to it. EMILY SHAK: Mhm. EMILY FORTUNA: Let’s see. EMILY SHAK: Something like that? EMILY FORTUNA: Yeah,
looks good, looks good. And I actually– before I
started using this plugin, I was checking the response
on issues and stuff. And the plugin maintainer seems
to be quite quick and stuff. EMILY SHAK: Oh, good. So we may get an update
for the next episode. EMILY FORTUNA: Yes. Yes, stay tuned. All right, for now
though, we will go back to watching on the entire table,
which is a little disappointing because it’s a little
less efficient than what I might have hoped. But it is what it is. EMILY SHAK: Can you not
just do command backslash? EMILY FORTUNA: I did
not know that one. EMILY SHAK: You– EMILY FORTUNA: Select these? EMILY SHAK: Select
those three rows. EMILY FORTUNA: OK, then there. EMILY SHAK: This one. EMILY FORTUNA: Oh. EMILY SHAK: Backslash. Yeah. Right. Write it up. EMILY FORTUNA: Oh, nice. Thank you, Emily. EMILY SHAK: I got you. EMILY FORTUNA: This is why
pair programming is awesome. EMILY SHAK: We have found
so many keyboard shortcuts that the other one
didn’t know about in prepping for our I/O talks. EMILY FORTUNA: True story. EMILY SHAK: It’s
been really helpful. EMILY FORTUNA: True story. All right, so OK, I can take
out my rebuilding, debugging. I think I might have had another
print statement in here from– print everything. Yeah, we can get rid of that. EMILY SHAK: That’s a fun method. [LAUGHTER] EMILY FORTUNA: Print the world. OK. All right, now we should have
less things spewing in our– OK, so back to what we were
originally intending on doing. We can favorite things,
but the whole idea was we want to have a Favorites
page that we can go back to look at so we can read
these favorites later. The question is, UI design. Where should we put it? EMILY SHAK: Yeah,
so I could imagine that it could be a third
tab in that bottom tab bar. It could also be
some other page that gets pushed over the
others, and you trigger that from some other menu. But I’m not a designer. EMILY FORTUNA: Me neither. EMILY SHAK: Designers, super
important for your team. EMILY FORTUNA: Yeah, so
I could see it being– you’d have a third tab
at the bottom here. We could have the
hamburger menu thing, where you have the three
lines as a dropdown. And you could have your– it’s a little different because
these are externally provided, whereas like Your Favorites
is a personal thing. You could also have
a Preference menu. The good thing is– EMILY SHAK: Yeah,
I mean, if we think we want to add a Preferences
menu at some point, maybe we have a bunch
of settings or things we could be looking
at in some menu, and this could be
the first of many. EMILY FORTUNA: Yeah, I
suppose you could also theoretically have things– we could check if
Moor does this, but you could have
a maximum database size for how many
articles you’re allowed to save, so that your app– if you’re an “article hoarder,”
you’re just saving everything, this app could slowly take
over all the storage space on your phone. So that could be a preference. EMILY SHAK: I mean, kind of
your fault at that point. [LAUGHTER] You know what you did. [LAUGHTER] But sure, sure. EMILY FORTUNA: I’m just
starting to think of settings. We could also have offline
syncing or something, or weather settings
could be set. EMILY SHAK: I want
to see a dark mode. EMILY FORTUNA: Ooh, OK. Just because of that, we’re
having a Settings page. OK, so we will add– let’s do a little hamburger
button thing in the top corner. EMILY SHAK: OK. EMILY FORTUNA: Maybe scooch our
little loading indicator over, and then– EMILY SHAK: Yeah, what
is the why right now? EMILY FORTUNA: So
basically, it’s indicating– EMILY SHAK: Ah. EMILY FORTUNA: Although
we also have this. EMILY SHAK: Oh,
that’s kind of fun. EMILY FORTUNA: Yeah. Oh, that’s fun. I think Philip was saying that
this occasionally happens, that we need to deal with it. But keep going and try again. EMILY SHAK: It’s
just kind of flaky? It doesn’t always happen? EMILY FORTUNA: Yeah. Well, so that was a
deserialization error. So we were getting information. So this pings the
Hacker News API and– EMILY SHAK: I mean,
with this message, it looks like it
was getting null and it tried to serialize
it as an article. EMILY FORTUNA: Right. So we were getting– EMILY SHAK: So where are
we serializing those? Can we check for null? EMILY FORTUNA: Where
we’re deserializing? EMILY SHAK: Yeah. EMILY FORTUNA: Yeah,
so I imagine– yeah, we should just be
able to add that. Deserialize. Is this our code? Not value, not let’s build IU. Get article. Here we go. EMILY SHAK: So in that
function, could we check to see if the string is null? And if so, just
return null, and then expect that from the caller? EMILY FORTUNA: Yeah, iterator. I just want to
check to make sure– where is the iterator? Because I want to
make sure that it’s– I want to ensure what–
or know what is null. If it’s the whole
string or if it’s a part of the string– a
portion in the string, you know? Where is iterator? Try calling iterator. Oh, object is iterable. OK. EMILY SHAK: I want
to say that just means that it’s trying
to iterate on an object, and the object is null. But we’re not going to
see an explicit call to something called iterator. EMILY FORTUNA: Right. Well, we’re calling it iterator. Iterable. EMILY SHAK: Yeah. EMILY FORTUNA: Yeah. So this is the iterator. But I guess what I’m asking
is, is the whole string null, or is that piece null? And so that’s why I
wanted– well, OK, let us– we can check. Parse article. Let’s just have a– if JSON string is null,
we skipped that article because it’s garbage. Where does this get called? Find Moor references. So caching articles on our test. Really? It’s only in– oh, it’s cached. [INAUDIBLE] EMILY SHAK: So just check if
storyres.body is null here? And then don’t do
anything if it is? EMILY FORTUNA: Yeah. Well, I just want to see where
this is called this article ID. Do we handle this? No, we don’t. Thanks, guys. We can say where– we can return null, and
then filter where not null. EMILY SHAK: Yeah. EMILY FORTUNA: That’s kind
of a crappy way to do it, but it’s what we’re
going to do right now. Where article [INAUDIBLE]. EMILY SHAK: And then
I think we still need to go into the
call to get article. EMILY FORTUNA: Yes. OK, so if storyresult.body
is null, then you should– do we want to throw this error? EMILY SHAK: Yeah, I
mean, now that we’re OK with it being null– EMILY FORTUNA: Yeah. EMILY SHAK: Not knowing the
history of that error at all. EMILY FORTUNA: Me neither. So long. OK, so storyres.body
is not null. And so otherwise,
we’re just going to– do we want
to set it to null? EMILY SHAK: I don’t
think we need to, right? EMILY FORTUNA:
Yeah, you’re right. Because it will,
by default, return null if there’s nothing there. OK, I’ll do a hot restart
just for grins on that. And hopefully, we
never see that again. Let’s see. Great. We fixed it, for sure. OK, onto what we
were going to do. EMILY SHAK: Yeah. EMILY FORTUNA: Hamburger method. So I forget what that’s
called, the hamburger menu. Do you remember? It’s like the tail
dropdown menu. Side menu. Flutter material– EMILY SHAK: Looks
like it’s a drawer. EMILY FORTUNA: So
that’s the actual thing. But can you specify the icons? EMILY SHAK: Oh. Yeah. EMILY FORTUNA: I’m just
asking about the icon. EMILY SHAK: You’re just
looking for the icon. OK. EMILY FORTUNA: I mean,
oh, but yeah, we should– we can use a drawer. Let’s use a drawer. EMILY SHAK: Cool. EMILY FORTUNA: Do
the whole thing. OK, so they have– oh, they just specify like
that and it does everything. Amazing. OK so– EMILY SHAK: Yeah, and the
drawer can have children. EMILY FORTUNA: OK, great. EMILY SHAK: Or one child. EMILY FORTUNA: OK, so drawer. I have never used a drawer. Drawer. And then list view. EMILY SHAK: Where? EMILY FORTUNA: Oh, I see. EMILY SHAK: I mean, at
this point, it’s up to us. EMILY FORTUNA: Yeah. Well– EMILY SHAK: We can just have– EMILY FORTUNA: We’ll
just have our one. So we’ll have Favorites page. Let’s just have
text to start with. Favorites page, and
we’ll do something– we’ll make that a real
thing in a minute. OK. Why did that not appear? Do you think it’s because we
have our Y Combinator thing? Let’s look where that is. EMILY SHAK: Yeah,
where’s that being built? EMILY FORTUNA: Home. Let us use the widget inspector. No. I haven’t used Dev Tools
and VS code in a while. EMILY SHAK: And it shows. EMILY FORTUNA: Yeah, right? Downloading updates. There we go. OK, so we want to– where’s my little–
oh, select widget mode. Go to simulator. Add bar, loading info. EMILY SHAK: I think you’ve
transposed the F and the O in your search query. EMILY FORTUNA: Oh, thank you. Oh, I found it. OK, so loading info. Where’s that put in the app R? Oh, OK. Scaffold leading. Can we not have a leading and
a drawer at the same time, so that maybe– I’m going to make it go away for
a second and see what happens. Oh, yeah. Apparently not. EMILY SHAK: Hm. EMILY FORTUNA: That’s sad. But we have to have it. Maybe I can stick it next
to the title or something, or off to the side of the title. Is that terrible design? We will be sad if
we have two things. EMILY SHAK: I’m just
wondering like– EMILY FORTUNA: Too much stuff? EMILY SHAK: Well, it
would be super cool. I bet we can’t do it
right now, but it’d be super cool if the hamburger
menu icon was the same as the Y Combinator menu. And so when you went
to the loading thing, it flipped over
and showed the Y, and then flipped back to the
hamburger menu and became– EMILY FORTUNA: Mm. We could do that with
an animated switcher. EMILY SHAK: Ooh, I’ve
never used one of those. EMILY FORTUNA:
Basically, it toggles between two different
things– two widgets. Let’s try it. EMILY SHAK: OK. EMILY FORTUNA: We’ll
see what happens. Meanwhile, people
at home are like, I just want a Favorites page. EMILY SHAK: The
loading info is already doing some animation
itself, though, right? EMILY FORTUNA: Yes. EMILY SHAK: So we would need to
strip that out or not use that? EMILY FORTUNA: Well, I
think it would be cool if we could still swap habit
spin and then swap back. EMILY SHAK: OK. OK, cool. EMILY FORTUNA: Do you think? What do you think? EMILY SHAK: No, I’m just– I don’t know what it’s
going to look like, but I’m excited to find out. EMILY FORTUNA: Well, I
don’t quite know either. We’re going to– yes, we’re
going to discover this. OK, so let us– I’ll just copy that. Drawer. So right now, that’s a thing. It’s not what I expected. EMILY SHAK: What? Oh, yeah, probably we need some
container that makes it white or something. EMILY FORTUNA: I guess. EMILY SHAK: I don’t know. EMILY FORTUNA: Why are
you not doing this? There we go. Wrap as container. [INAUDIBLE] And let’s just make
it a height of 300 because that’s arbitrary. No, I’m still in– erg. I’m in the select
widget mode thing. Dev Tools, cancel widget mode. Phew. OK. Yes. So now– oh, the Favorites
page is way up there. OK, that’s not
important right now. EMILY SHAK: Exactly what
we wanted to have happen. EMILY FORTUNA: Yes. [LAUGHTER] That’s entirely what I intended. I just need to wrap
in a [INAUDIBLE].. It’s kind of interesting
that the drawer has its own– it’s not using [INAUDIBLE]. Anyway– EMILY SHAK: I mean,
it makes sense that you would want full control
over everything in there. EMILY FORTUNA: Fair
enough, fair enough. EMILY SHAK: With great power
comes great responsibility. EMILY FORTUNA: And great
design requirements. OK, so back to this
icon, let’s see. Can you specify
an icon in drawer? Custom? Oh, OK, no, but we
don’t need to do that. All we need to do is– so this we are listening for
whether something is loading or not with the Y Combinator,
little animator thing. And so what we can do instead
is we can still listen, and if it isn’t loading, have
it display the drawer thing. And if it is– EMILY SHAK: Is that going
to animate between them? EMILY FORTUNA: We can wrap
that in an animated switcher. EMILY SHAK: OK. EMILY FORTUNA: But
all of it comes from whether we are loading or not. EMILY SHAK: Mhm. EMILY FORTUNA: So I’m going
to copy this and go here. And close my parentheses. Another parentheses. OK, and when we figure
out what we’re doing, let’s make this not a one-liner. What have I done? Mm, trying container. EMILY SHAK: I wish there was
a plugin that could just say, you have a bunch of parens and
brackets that look messed up. Let me just go ahead and
match them up for you. EMILY FORTUNA: Fix them? Yeah. EMILY SHAK: That’s
probably the kind of thing that’s like impossible
to do, though. EMILY FORTUNA: We should
work on that, for sure. OK, so container [INAUDIBLE]. OK. Text, container, drawer,
semicolon, bracket. Do we just delete that? Is that the– EMILY SHAK: Cool. EMILY FORTUNA: OK, phew. OK, so we are listening for
whether it’s loading or not. And I think loading info
is doing all this checking states right now. What are we doing with– [INAUDIBLE] value
notifier is loading. Where does this get called? Oh, so we add a listener,
and this returns nothing. It would be nice if
this were a stream. I think I had this as a
stream and it got changed. So loading tabs counts is an int
of the tabs that are loading. I guess– oh, wait. OK, so consumer of
the provider package, it gets called whenever
this value changes. So I think all we need
to do is check the value and do something. If it’s 0 versus greater than 0. EMILY SHAK: Cool. Sounds good. EMILY FORTUNA: So
let us do– we’ll wrap this in animated switcher. Animated switcher. And we will say,
[INAUDIBLE] is loading. This is kind of repetitive. Loading is greater than 0. Oh. Loading tabs count. What is that? Dot value. Great. OK, and then animated
switcher, you take– your child is dependent on– so is loading. If it is, we want that loading
info, I think it’s called? Yeah, loading info– loading. EMILY SHAK: Oh, an
animated switcher just takes one child rather
than the two things that it’s switching between? EMILY FORTUNA: Yeah, it’s
a little funky that way. And then I think we need– what is it complaining about? Duration. We need a duration. Duration, duration. Let’s make it– EMILY SHAK: 150 milliseconds. 500 milliseconds. Some number. [LAUGHTER] Perfect. EMILY FORTUNA: OK,
so half a second. So in theory– now, these
may have already loaded, so it may not do anything. EMILY SHAK: Although that
one looked like it was– EMILY FORTUNA: It looks
like it was loading. I didn’t do anything. OK, so let’s just, for
grins, print this out. Print. Is loading. Oh, wait, no. That works, but we’ll also
just print the loading value because that’s kind of
where our source is. And where’s our output? Well, those are things. Let’s do hot restart just to
try and clear the cache here. That’s great. Oh. Hm. Did our error catching go awry? EMILY SHAK: Are we seeing
any error messages? EMILY FORTUNA: No. Then again, we did
delete that row. [LAUGHTER] That’s great. Let’s try starting afresh. EMILY SHAK: We dream too big. EMILY FORTUNA: Yeah, we do. [LAUGHTER] Well, all else fails, we
did get our stream working, and we have the
beginnings of this. Yeah. But gosh. OK, look at this. So animator switcher,
duration is loading. That all looks reasonable. OK. EMILY SHAK: OK, so that worked,
but it didn’t show the loading. And are we seeing any prints? All right, so that’s not
updating like we think it is. EMILY FORTUNA: Yeah. This is not getting– it’s not firing. Sigh. OK. Loading tabs count is
clearly not doing– is not what we think it is. Let’s take a look at it. Well, that’s an exciting
function, [INAUDIBLE] class. EMILY SHAK: Is that just always
creating one with nothing? I mean, what’s that
0 feeding into? EMILY FORTUNA: It’s
value notifier. So we’re saying the
starting value is 0. It’s extensive value
notifier, which is just a little thing that pulls– EMILY SHAK: Oh, but it will
update with a different value. EMILY FORTUNA: Yeah. But the question is,
who’s updating it? So find all references. Loading. It’s passing it in there
to a Hacker News tab. Is loading. So let’s look at
Hacker News tab. Where’s the constructor
to this thing? EMILY SHAK: The Hacker
News tab constructor? EMILY FORTUNA: Oh, there we go. Loading tabs count. Final. Oh, here. OK, refresh. EMILY SHAK: Why are we
notifying the listeners before we change the value? EMILY FORTUNA: That’s
a very good question. Let’s move that up. Yes, it seems to– wait, or notify it
here too, though. EMILY SHAK: Also,
yeah, I’m confused about why there are two
notify listener calls in here. EMILY FORTUNA: That
feels very incorrect. EMILY SHAK: It feels
like maybe we just need to get rid of the first one. EMILY FORTUNA: Yeah,
I think you’re right. EMILY SHAK: Because
everything else is changing. EMILY FORTUNA: OK. So I’m going to do a hot restart
again to blow away my caching. It’s still not updating and I’m
not getting a print statement. Grrr. EMILY SHAK: Oh,
well, I’m noticing that we’re incrementing
and decrementing it. EMILY FORTUNA: Oh, my gosh. EMILY SHAK: Do we
need to be notifying listeners every change? EMILY FORTUNA: I have never
used notifier listeners multiple times in
a single function. EMILY SHAK: Yeah. But I guess, since
it’s asynchronous, it kind of makes sense, if we do
it when it’s up and then again when it’s down. I’m wondering if we need to move
that call below the decrement of it, and then also have
another one that’s right after it’s been incremented. EMILY FORTUNA: Yeah, so
the way it was originally– EMILY SHAK: It feels
strange, though. EMILY FORTUNA: It was like this. We set [INAUDIBLE] to True. Noti– but wouldn’t you put it– oh, whoa. Why wouldn’t you put
this below that one, and this below that one? EMILY SHAK: That’s
what I’m wondering. EMILY FORTUNA: Let’s try that. Let’s do a hot restart. Oh, fun things. Field host lookup. Good grief. So we’re getting that
information there? Interesting that
we’re– let’s see. Socket exception. So we need to– instead of
just checking for the 200, we need to do try
on socket exception. And I want to do
on socket exception or if the status
code is not good. But I don’t know
that we can do that. We could throw another
socket exception. That seems really
bad and dumb though. Fine. I’ll just– can we make this a– let’s make this a function. The error function. And then we’ll just say
on socket exception error and if [INAUDIBLE]– oh, gosh. OK. I don’t like that code. EMILY SHAK: Yeah. It’s also not really
the kind of thing that we are going to
know if it’s working. EMILY FORTUNA: Right. OK. So we changed some stuff. Let me take out my
drawer thing to see if, when I move those
notify listeners, it still works as we
were seeing it before. EMILY SHAK: OK. EMILY FORTUNA: And then we can– I know we’re running out
of time a little bit. So I want to– but we can at least
make some progress. So let’s cut this. Or I guess we’ll leave it
because we need to follow up about the bug report. EMILY SHAK: Mhm. EMILY FORTUNA: I will just– let’s command
backslash, good that. Oh, return. OK, and hot restart again. What have I done? Oh, I didn’t comment
that out too. Phew. EMILY SHAK: So we’re
still seeing a drawer. EMILY FORTUNA: I
still have a drawer. EMILY SHAK: Is it– wait, where are you building
the Y Combinator thing? It’s under this drawer argument. Is that a problem? EMILY FORTUNA: I thought
it should be OK, but– OK, let’s– EMILY SHAK: What if
we were to put that under the leading argument? Because I’m wondering if leading
is just a way to have something there that can do anything. And we could have a drawer
widget that builds there, and then maybe that’s
the same kind of thing. EMILY FORTUNA: True. EMILY SHAK: Maybe that’s
why it hasn’t been working. EMILY FORTUNA: But
why is drawer funky? We should read
the documentation. OK, so that works as we– it animates as we expected. When you– that first time. EMILY SHAK: OK. EMILY FORTUNA:
Because it’s loading. So let’s take a
quick– so I know we are running short on time. Let’s take a quick look at
the drawer documentation and we can– EMILY SHAK: I
actually have it open. EMILY FORTUNA: Perfect. We can plan for what we’re
going to do next time. EMILY SHAK: OK. EMILY FORTUNA: Let’s see. [INAUDIBLE] design. EMILY SHAK: Oh, OK,
a drawer class– no. [INAUDIBLE] Interesting. Oh, so this expects a lot
about what its children are. EMILY FORTUNA: Mm. EMILY SHAK: Though it may be
that it works without those. EMILY FORTUNA: Yeah. EMILY SHAK: And then
there’s scaffold.drawer, which is what we’re using. So a little hard to
say what scaffold is expecting about
what’s behind there. But if you can use
scaffoldstate.opendrawer to open it, then that
must be at least something that is openable. It might be imposing a
drawer widget in some way. EMILY FORTUNA: Oh, so
we’ll do one more thing. Let’s test– let’s
make this a leading. EMILY SHAK: Right. EMILY FORTUNA: Yeah, which
is what you’re saying. How do I undo? Is it this? EMILY SHAK: No,
it’s the same one. Same command. EMILY FORTUNA: Oh. OK. EMILY SHAK: It just
toggles between them. And then I think if you
have some comments and some not in the block, then it adds
another comment to everything. EMILY FORTUNA: Yes,
I saw that before. OK, so let’s make this leading. It doesn’t like that because– EMILY SHAK: Have you
already defined leading? No. Is this not inside the scaffold? EMILY FORTUNA: That
might be dangerous. Let’s see. Leading. Oh, it’s supposed to be App Bar. Well, that’s a good start. I’m a little scared about
doing this, but here we go. Leading– phew. Oh. EMILY SHAK: OK. [LAUGHTER] EMILY FORTUNA: That’s a thing. EMILY SHAK: So what did
we expect to be there? EMILY FORTUNA: Oh, wow. OK, so drawer is doing
a lot under the covers. So it is– because
it is not loading, it is showing us a drawer. But there’s something
about scaffold that knows when to
put the drawer thing– I think scaffold
must be hard-coding that little hamburger menu. Because this is showing
us literally the drawer. EMILY SHAK: Yeah. I wonder if what we
need is to have this be an icon button or something. And then when you press it,
we do the drawer operations manually. EMILY FORTUNA: Yeah. We should– OK, so let’s
just put a little comments as a to-do. EMILY SHAK: Yeah. Can I see if, at least, the– EMILY FORTUNA: Oh, yeah. EMILY SHAK: –loading
thing is working? EMILY FORTUNA: So let’s
do refresh or restart. EMILY SHAK: It was
going to be so good. We’re printing a bunch
of 1’s here though. EMILY FORTUNA: Yeah. EMILY SHAK: So are
we not updating when it gets back to 0? EMILY FORTUNA: Oh, maybe– oh, yeah. Oh, maybe my thing
is wrong, although I would think it should be– it’s only 1. EMILY SHAK: Did it ever
print a 2 up above? EMILY FORTUNA: No,
it’s only that. EMILY SHAK: Oh. EMILY FORTUNA: It never
printed 2, never printed 0. OK, so to-do’s. We’re going to have– let’s– to-do. Loading value– why
is it never not 1? And then make a separate to-do. EMILY SHAK: I mean,
interestingly enough, it did show the drawer
before we hot restarted. So at some point,
that value was 0. EMILY FORTUNA: But it
wasn’t being notified. EMILY SHAK: I’m wondering
if we’re not notifying about the change back to 0. EMILY FORTUNA: And yet,
we set that thing again. Where was that? That was in– change the value. This is a question for Phillip. He is the– EMILY SHAK: Yeah, I
want to understand this refresh function
better, if there’s some reason that the notify
listeners were where they were. EMILY FORTUNA: Yeah. OK, so make an icon button. EMILY SHAK: That
opens up a drawer? EMILY FORTUNA:
That opens a drawer because scaffold hard-codes
a drawer right here. OK. EMILY SHAK: And then make
a whole Favorites page. EMILY FORTUNA: Yes. [LAUGHTER] EMILY SHAK: That one’s
maybe a couple episodes out. [LAUGHTER] EMILY FORTUNA: We’ve got
our work cut out for us. All right, so thank you so much. In summary, what we did
was we cleaned up our– oh, look, the Favorites
page is there again. EMILY SHAK: Great. Did it– when? Did you– EMILY FORTUNA: When I
saved and it hot reloaded. Because I guess the value is 0. It’s not being– so that’s– that value notifier is
functioning strangely. It’s not notifying
every single– EMILY SHAK: Yeah. EMILY FORTUNA: I think it’s– I wonder if that notify
listeners is getting optimized out so it gets called– is that getting
compressed or something? EMILY SHAK: But you would think
that the second one, then, would be the one that
takes precedence, right? EMILY FORTUNA: OK, wait. Let me test one
more thing before– I keep trying to wrap this up. All right, let’s move
it back to where it was. Let me get diff or get status. EMILY SHAK: I mean, they
were both just moved right above where they are, I think. EMILY FORTUNA: I know. I just want to check
because I don’t trust– I don’t trust myself. EMILY SHAK: I do have the
code open on my machine. EMILY FORTUNA: OK. Yeah, you’re right. It’s up one line each one. EMILY SHAK: OK. EMILY FORTUNA: So
Hacker News API. x. OK, let’s do hot restart. OK. OK, so the notifications
is not what we think. Other trick, so I
can see– get blame. Oops. I copy/pasted. So we know who to ask. Filler. EMILY SHAK: It’s a
pretty clear filler. [LAUGHTER] EMILY FORTUNA: Listeners. Yeah, all right. Philip, we got some
questions for you. So in summary, we fixed
up the database stream. EMILY SHAK: We filed that bug. EMILY FORTUNA: Yes,
we filed a bug. We delved into drawers and
learned a little bit more about how they work. We got a little too
tricky for our own selves. EMILY SHAK: We may have
ended with more questions than answers. [LAUGHTER] EMILY FORTUNA: But
that just gives you something to look forward
to for the next episode. Yeah, and in theory,
what we want to do is we’ll have this
drawer that can swap between the
little three lines for a dropdown menu and
the Y Combinator thing. But the loading tabs counts
was not doing what we expected, so we need to
investigate some more. So stay tuned on this
exciting cliffhanger ending. [LAUGHTER] There’ll be more to come. See ya next time. EMILY SHAK: Thanks for watching. [MUSIC PLAYING]

26 thoughts on “Custom Drawer, Filing Bugs, Working with Databases (The Boring Flutter Development Show, Ep. 27)

  1. Why is the title misleading? 😕 I found no reference of custom dropdown in the video. Is it supposed to be drawer instead ?

  2. I forked the insta-flutter repo from you emily. Very nice 😊👍🏼. But there's a local reference in the pubspec.yaml. Corrected it to your forked fluwx repo. And in the fluwx .m file there was also an absolute path. corrected that also and it worked. Thanks for all your public projects 😊

  3. That Fuschia symbol's enveloping the Apple symbol on left Emily's macbook xD Is that a sign of something to come lol?

  4. I have a handy keyboard shortcut for you Emelies.

    Move a line up or down instead of copy, delete, paste.
    ⌥↑ or ⌥↓

  5. Is there any particular reason why you (and the other devs featuring in other episodes) are using VSC rather than Android Studio? It seems to be a bit barebone compared to Android Studio.

  6. @Flutter:

    Can we have a "Good Morning" text like in this mock-up:


  7. Maybe its not a bug in Moor, you were watching nothing and expected that the ui was updated. You could solve that using a different database schema, in which every Record is in the Table and isfavorite is a column. Does it make sense? Thanks for the great video.

Leave a Reply

Your email address will not be published. Required fields are marked *