MATT SULLIVAN: Hello, everyone. I am Matt Sullivan, a developer
advocate on the Flutter team. EMILY FORTUNA: And
I'm Emily Fortuna. I'm a software engineer
on the Dart team. MATT SULLIVAN: And
so what we're going to do for the next 30 odd
minutes is we're going to live code a Flutter app, and yeah. We're-- hopefully this is going
to go smoothly, but this is-- we're going to start from the
very basics and go all the way through. So we're just going
to see what happens. There will be no slides. This will just be code, except
for this slide, of course. And we'll see where we get to. So what are we going to build? EMILY FORTUNA:
Well, we are in LA and I am so looking
forward to checking out the food scene around here. I mean, I just had
some food here, but I need to plan
ahead for dinner. And I'm very particular because
when I get hungry, I get angry. I might even get hangry. Do you think we could
write a Flutter app that could help us out with that? MATT SULLIVAN: So I think
what we maybe want to write is a Flutter app which
finds local restaurants, shows them to us, shows some
ratings, that kind of thing. EMILY FORTUNA:
Yeah, let's do it. MATT SULLIVAN: OK, so
do you want to start-- EMILY FORTUNA:
Yeah, I'll do that. MATT SULLIVAN: OK. So what we're going to
do is we're literally going to start from
scratch and we're going to create a
new Flutter app, and we're going to
call it Nom Nom. OK. We are going to be
coding pretty quickly for the next half an hour. We're going to be breezing
through a lot of stuff, and we're not necessarily going
to stop and explain everything because what we really
want to show you is kind of the flow of how we develop. How do we use hot reload? How do we use the
tooling that we have? And so there will be plenty
more talks on Flutter and various aspects of it. We'll be around
afterwards and we'll have the code up on GitHub. Help. So if we breeze over
things that you might miss, then bear with us. We'll get to the end. We'll answer any
questions afterwards. So what Emily has done is she
has created the out-of-the-box Flutter app, and what are
we going to use as an ID? EMILY FORTUNA: We
are using VS Code, and you know, it's no
Vim, but I'll accept it. And yeah, you can see
other IDs at other parts throughout the conference--
that we thought we'd show something different. MATT SULLIVAN:
Yeah, so there will be talks on Android
Studio and IntelliJ, and they will be using it. But we kind of wanted to
use Visual Studio Code. It's my IDE of preference, so
for the person out there who built the plugin,
we really apologize for what we're about to
show, in case, you know, where we go with this. So what we have is we have
fired up the out-of-the-box app. Now, you may have noticed
that that took maybe eight to 10 seconds to compile. That's the initial
build because it's got to do all the Android-y
stuff and package the APK. But you'll see,
in terms of how we develop with that,
that's not going to be the case going forward. So what we have-- Emily stripped out
all the handy comments that we've put in, to help
you with your initial app. And so, OK, we
have a Flutter app. So why don't we change the name. And there we go. Hot reload. Emily hit save. About half a second
later, that kicks off. So changing a name
isn't that awesome. We'll be doing other stuff which
will be pretty cool later on. So let's get rid of
all the boilerplate that we have in there
for this default app, and we're going to bring
it back to Hello World. So we're basically going
to strip it all out. We're going to create
a new text widget because this being
Flutter, all of the UI is composed through widgets. And again, we'll show you
some of that as we go forward. And there we go. So we stripped it back. So we have the most,
pretty much, basic app you can imagine. It's got a very small-- can everyone see the--
is this big enough? AUDIENCE: Yeah. MATT SULLIVAN: OK, cool. So we are back to Hello World. So what's the
first thing we need to do to get this app going? EMILY FORTUNA: Well, let's
create some dummy restaurant text that we can fill
in to start with. MATT SULLIVAN: OK. Cool, so for Hello World, we're
reusing the stateful widget that the out-of-the-box
app gave us. You don't need a stateful widget
for things like Hello World, but because we're going to build
a list of restaurants that's going to update, we're going to
need to be able to track state. So what we're doing
now in our state is we've got a list
of strings that's going to hold our
restaurants or our places. And we're going to
initialize that through the-- by overwriting in its state. And we're going to
populate that with probably a bunch of strings, just
so we can get the list up and running. And as you can see, as Emily is
typing this, the Visual Studio plugin-- notice how it's
recommending things, how when we hover over
things, it gives us the constructor and whatnot. And it's how the excellent work
that the tooling team has done to be able to enable this, so we
can put this into multiple IDs. So great. We have got some state
now, and we have a list of-- what's that going to be? 100 dummy restaurant names. So I guess we're going to
swap that out of our texture. What are we going to
use to show the list? EMILY FORTUNA: There's
this list view widgets, and you can just pass
in a list, and it will display all those children. So-- MATT SULLIVAN: Perfect. So we're going to
use a list view. Now, if you have developed
on other mobile platforms, sometimes, like, creating
performant scrolling lists can be involved. The nice thing with Flutter
and the Flutter widgets is that we've taken
care of that for you. So Emily has created
a new list view in place of the
Hello World child, and notice that,
again, we have to use widgets to compose the UI. So as opposed to just
rendering the strings, we're creating a
new text widget, and I'm not talking fast enough. You're typing faster than-- OK, that's fine. And we have a really
uninteresting and kind of ugly list of strings. EMILY FORTUNA: I'll
point out also, I had to do a full restart there,
as opposed to the hot reload, and the reason for that is hot
reload is great for existing objects that have
already been built. But we added this places list,
and so to create that, we needed to do a full restart. MATT SULLIVAN: So
rule of thumb always is that when you're working
with widgets and UI, hot reload is great. If you change your
state, programmatically, or you change the code rendering
your state, do a full restart. But how long did the
full restart take? EMILY FORTUNA: Let's see,
it only took just barely over half a second. MATT SULLIVAN: There we go. So hot reload and full restart-- it's all going to be subsecond,
in terms of updating. So we have got a
list of strings. We have our app, but we kind
of need to get some data. EMILY FORTUNA: Yes. Matt, would you like
to take the keyboard? So we're going to be
using the Google Places API to get information
about a specific location and return restaurant data. Now because, alas, poor
Matt does not speak URL, we are going to be
copying in a places file that has the
URL we're going to be using to request that data. So I mentioned
this place is API. There's a couple of
ways you can call it. There is the HTP RESTful API. But there's also iOS and
Android API, as well. But since we're going to code
it all in Dart, we got this. All right, so Matt has
pulled up this places file. It's a standalone file, so we
can run it from the command line and you can see what
data we're pulling down first, and then we'll hook it
up to our Flutter app. So we've got a main,
we've got a place class. It has a name, rating,
address, and then we've got our little constructor
and a nice two string for the results. All right, so down
to get places, which is where the
interesting stuff is, here is this URL that we did
not want to try and remember. MATT SULLIVAN: Yeah,
I can't believe you didn't think I
could remember that. EMILY FORTUNA: Yeah, well. MATT SULLIVAN: Look at it. EMILY FORTUNA: Sorry. Maybe next time. So we've got a location
for latitude and longitude. In this case, we're passing
in some dummy coordinates for Venice Beach, which is
where our current location is. And then, we're going to make a
request to give me restaurants all within 500 meters of this
specific geographic location. And then we're passing
in this key, which tells Google Maps, hey, this
is who's making the request. MATT SULLIVAN: Nobody gets
to see my private key. EMILY FORTUNA: Yes. So to do this call, we're going
to be using the HTTP library. You probably want to-- we need a package. MATT SULLIVAN: I need to
add the dependency, right? EMILY FORTUNA: Yes. MATT SULLIVAN: OK. EMILY FORTUNA: So
to do that, we're going to open up
our pubspec.yaml, Specked and Matt's going
to add this HTTP library. And you see this
little carrot here that's saying I'm going to
use anything 0.11.3 or above. And then on save, it pulled
down the package right there. MATT SULLIVAN: Handy
feature, again, of the IDs is that it's automatically
pulling the packages, as soon as I edit the pubspec. So we should be good to go. EMILY FORTUNA: So
back on places, we now have the package. Do we have the import? MATT SULLIVAN: Mm-hm. EMILY FORTUNA: We
have the import. Cool All right. Scroll down again. And so, getting HTTP information
is pretty easy with Dart. You just call HTTP.get pass URL,
and then you pass in a callback that you want to be called
when you get your results. In this case-- so it
returns the future, and you call-- in this case, we
are printing out the results. So Matt, you want to run
this on the command line? MATT SULLIVAN: All right,
let's get this running. EMILY FORTUNA: All right. Unreadable JSON. MATT SULLIVAN: We
have some JSON. End of presentation. There we go. JSON. Done. Woo. [APPLAUSE] EMILY FORTUNA: So OK. So we've got some JSON. Now if this were an
interview problem, your next step would
be to parse all this into [INAUDIBLE] objects. But because this is not
an interview problem, we are going to use
the Dart streams API-- MATT SULLIVAN: Yes, we are. EMILY FORTUNA: --to parse
this JSON in a nice way. So you see the code down here. We are creating our HTTP
client, making the request, and then we're creating
the stream API. So for all of you people that
are very familiar with Dart streams, they're old hat. But in case you're
not, the difference between streams and futures
are they're both asynchronous, but a future is returning once,
whereas a stream is returning multiple pieces of data. So in this case, yes, we're
making that HTTP request and we're returning once,
but then what we want to do is turn that stream
into a stream with multiple pieces,
where we are returning each individual
restaurant that is in the results as an
item in the stream. MATT SULLIVAN: So how are
we going to break this down? EMILY FORTUNA: So
we are going to call this transform to decode the-- because yeah. If you print it
out right now, it will just be a bunch of bytes. MATT SULLIVAN: Let me
quickly show that I've got some stuff done here. So we listen to the stream and
then we close it on [INAUDIBLE] Actually, let me show
you with just the bytes. EMILY FORTUNA: If you
can't read URL bytes. MATT SULLIVAN: Here we go. That's even better. EMILY FORTUNA: Yeah. All right, so back
to transforming it into interesting things. So let's go back
to transforming it into a readable string
with that UTF decoder, and we can transform
it into a JSON object. MATT SULLIVAN: Yep. EMILY FORTUNA: And
then we're going to call this expand
method, and this is where we're taking that
one JSON response and, like, parsing it out into individual
restaurants from the results. MATT SULLIVAN: And the nice
thing about this-- this is a real world example
using the Google Places API. There's a lot of metadata in
the JSON, so what you see here is we really want the
results list, which is embedded in the JSON object. So we're digging
in, we're making sure the typing is
correct, to make sure that it knows the
JSONBuddy is a map, and then we're expanding
the individual pieces and the results to get
out a whole bunch of not-- EMILY FORTUNA: JSON objects? MATT SULLIVAN: Yes. Thank you. EMILY FORTUNA: Yeah. And so now we have these JSON
objects of restaurant results, and we want to
make place objects. And so that's what this
map method is about. We're constructing a new
place from that JSON. Cool. So now, if you print
it out, you should get-- we can make use of
that nice two stream method. MATT SULLIVAN: So we have
gone from a bunch of bytes through streams to a bunch of-- EMILY FORTUNA: All right MATT SULLIVAN: --places. Yay! EMILY FORTUNA: We can
use an HTTP restful API! OK. So let's get to
the exciting stuff. Let's put this
back up to Flutter. MATT SULLIVAN:
Let's do more HTTP. That's awesome. EMILY FORTUNA: OK. So we do this. We want to return the stream
that we just created-- MATT SULLIVAN: Oh dear. EMILY FORTUNA: --to
our Flutter app. MATT SULLIVAN: So I'm
going to be returning what? A future? EMILY FORTUNA: Return
to your future. MATT SULLIVAN: It's going to be
a stream, which I can't spell. And it's going to be
a stream of place. Cool EMILY FORTUNA: Yeah. And then yeah. Cool. So let's go back to main. MATT SULLIVAN:
Well, we're actually going to write some
Flutter again, are we? OK. Good, good. Do I get to code now and not
just comment and uncomment things? EMILY FORTUNA: Do. MATT SULLIVAN: Pressure. OK. EMILY FORTUNA: All right,
so back in our main app, we want to call this
get places call. So in its state, let's
make a function called, listen for places. And then, let's define that. And since that get places
is going to return a future, this is async, yes. MATT SULLIVAN: Whoops. There you go. EMILY FORTUNA: And then we may
want to import our places.dart. But then we're going
to call it places. MATT SULLIVAN: Oh, we need to-- yeah. So we need to import our places. I got you. Places.dart. Am I talking while I code again? I do that. Yeah, sorry. OK, so listen for places-- async. I guess we're going to
grab the stream, yeah? EMILY FORTUNA: Yeah,
call it get places. And then we can pass in those
Venice Beach coordinates to start with. MATT SULLIVAN: All right,
let me get those coordinates, so we can just pass those in. OK. EMILY FORTUNA: All right. And you want to do a wait. MATT SULLIVAN: I do
want to do a wait. Why do I want to
do a wait again? EMILY FORTUNA: We're
getting this future, and then we want to just get
the stream from the future. And so it's a nice
way of saying, hey, don't proceed on
execution until the next step until I get that result. MATT SULLIVAN: But the result
is going to be the stream, not the full list of things, right? EMILY FORTUNA: Right. MATT SULLIVAN: Yeah, OK. EMILY FORTUNA: So now, our
stream-- we want to say, yes, we want to
listen to the stream, and we want to say, hey, for
each place object we get, we want to convert it
to a Flutter widget. Or actually, we want to add
it to our list, to start with. MATT SULLIVAN: We want to
add it to out list, OK. So I'm going to
add it to places, but that's going to be
the wrong type, so-- EMILY FORTUNA: Yes. Change to place. List of place. MATT SULLIVAN: And
let me fix this. OK. EMILY FORTUNA: In
places.add, right? There you go. MATT SULLIVAN: There we go. OK, good. EMILY FORTUNA: Cool. Now we want to scroll down
for where we're actually printing out the stuff, and-- MATT SULLIVAN: This is no
longer going to be a string. This is going to
be a place object, and let's print out the name. EMILY FORTUNA: Cool. MATT SULLIVAN: Uh oh. What happened? EMILY FORTUNA: We
added a bunch of state. We need to do a full restart. Oh, and we also
need to set state. We need to tell Flutter that-- MATT SULLIVAN: Oh, you're right. OK, so if I do a full restart-- EMILY FORTUNA: There's nothing! MATT SULLIVAN: Here's the thing. Like, programming
with Flutter-- it's like you do something
daft in your app, like I did, and it breaks and
it gives you some information, and then you fix it and you
do hot reload, and boom. There we go. We're back in. However, there's
nothing in the list because, as you
correctly pointed out, we don't actually tell Flutter
that our state has changed. EMILY FORTUNA: Yeah,
so because Flutter wants to be efficient
about redrawing, it won't actually redraw
until you call set state to say your state has changed. So now we say each time we
get a new place, redraw. MATT SULLIVAN: So this
should work, right? EMILY FORTUNA: Yes. MATT SULLIVAN: Yay, there we go. So now we have an ugly list,
but with actual, real data. OK. [APPLAUSE] EMILY FORTUNA: OK. MATT SULLIVAN: So we
could end it here, and the Flutter team
would be very sad. And this is a talk
about Flutter, so we should make
this look nicer. EMILY FORTUNA: Let's
make it look nice, yeah. MATT SULLIVAN: So do you
want to make this look nicer? EMILY FORTUNA: Yeah. MATT SULLIVAN: OK. So what we can do here is
we're showing a list of places. So why don't we
create a new widget which will render
these places correctly. And the thing here is that
these places are stateless. We're not going to be
dynamically changing them in real time. We're just going to
build the list of places. It will be fine. So we can use a stateless
widget, and what we can do is we can just, in
the constructor, pass in a place object
and we can use that, then, to build up the widget. So this is-- usually with
the stateless widget, make sure if you're
passing any data in, just make it final
because it's not going to change, anyway,
because stateless widgets are immutable. And so what we need to do in
order to make this look good is to override the build widget. And as you can
see, again, the IDE is, like, adding
the methods that we need to override, et cetera. And it's making-- oh, we
broke it again, did we? EMILY FORTUNA: Yeah,
well, build is not-- MATT SULLIVAN: Oh, OK. So we're rendering
a place widget and builders are printing
null, and Flutter is sad. So why don't we just-- EMILY FORTUNA: Build returns
null makes Flutter sad. So-- MATT SULLIVAN: What
are we going to use to make this look better? EMILY FORTUNA: We could use
a list tile, since we've got an item in the-- MATT SULLIVAN: So-- EMILY FORTUNA: --whole thing. MATT SULLIVAN: --Flutter
has a great collection of built-in widgets,
and we're just going to utilize those
to go from ugly list to something that is hopefully
more pleasant on the eye. So we have this thing
called a list tile. It takes a title,
so I guess we can make the title the
name of the place. And of course, you can't
just use the string, because things are
composed of widgets. So we're going to
wrap that in there. Hot reload. Boom. Now we have a nicely spaced
ugly list of strings. So what else can
list tile give us? EMILY FORTUNA: List
tile-- we have our root. We can do subtitle. MATT SULLIVAN: OK, so let's-- EMILY FORTUNA: And we can
add the address there. MATT SULLIVAN: Let's
add the subtitle and let's stick our
address in there. We're going to wrap that,
again, in a text widget. And, oh-- so this is
looking a little nicer. We've got our addresses. We're probably bored of
seeing text widgets, as well. So we should probably
use something else. So how do we get your
reviews up there? Because you want to
know what restaurants-- EMILY FORTUNA: I want
to know what's good. MATT SULLIVAN: Oh,
good or not good. EMILY FORTUNA: So we can
pass this leading parameter. It'll show things
before that text. We can pass in the circle avatar
and pass the rating in there. MATT SULLIVAN: OK, so we're
going to use a circle avatar. In this tile, we've got
this leading thing, which you'll see where it prints. And in the circle
avatar, I guess we're going to put the rating. EMILY FORTUNA: Mm-hm. MATT SULLIVAN: OK, and
again, because circle avatar is a child, we're
going to use text. And of course, our
rating is double and because we want to be
correct with our typing, we're going to make that
two straight-- oh, look. So that's looking
nicer, I think. [APPLAUSE] And so we've got 10 minutes
left, so we can stop. Now, what are you doing? Are we still going? Oh, you're changing the-- OK. OK. We'll keep going. There we go. OK, so what'll we do next? EMILY FORTUNA: Well, I want
to be able to easily look from these, based on the
color of the backgrounds, what are the really good ones? MATT SULLIVAN: So we're going
to update the color based on how good the rating is, and
we could do if, then, if, then, switch this, that, the other. We're not going to do that
because what we can use is we can use interpolation,
because a lot of the classes and widgets in Flutter have
interpolation baked into them, and what we can do with that
is we can use the color class. And we're going to linearly
interpolate from red to green, and we're going to
interpolate from 0 to 1, so if our rating
is 1 to 5, we're going to divide that by 5. And then, using that,
hopefully one line of code and hopefully this works, we're
going to pass in the rating. And-- EMILY FORTUNA: It didn't. It's-- so-- MATT SULLIVAN: OK, so
all of these restaurants are pretty close. So you're not going to
see-- you can see the-- OK. We're not being mean to this. They just don't
have any ratings. So we've given it a minus 1. Please go there. I'm sure they're wonderful. EMILY FORTUNA: Please rate it. MATT SULLIVAN: But the point
is that we have this nice-- in one line of code, we have
this blend from red to green. We can slide it straight
in, and this is how, like-- the joy of developing
with Flutter is we're messing
with these things. We're trying them out. We're trying new
things, and now we have your app, which
lets you work out where you would like to go or not go. Are you happy? EMILY FORTUNA: Well, once I
visit one, I want to, like, check it off the list, you know? MATT SULLIVAN: You want
to check it off the list? EMILY FORTUNA: Yeah. MATT SULLIVAN: OK. So with the 10 minutes
we have remaining-- nine minutes we have
remaining, we're going to make Tinder
for restaurants. We're going to swipe
right to like-- that's left. And the other way to dislike. And how are we going to do that? Well, there is a
dismissible widget that's handy in the Flutter library. Notice how, again, we use
the IDE to wrap the widget around the existing widgets. Again, it just makes
your life much easier. Dismissible takes a key,
and the reason dismissible takes a key is that
the dismissibles need to track what's been
dismissed and what's hidden. So in order to do that,
it has a key associated with each one of them. And-- oh! [APPLAUSE] It does things like that. I need to talk faster, clearly. And so this is great. We have this dismissible. We have a key, but I don't
know if swiping right or left is good or bad. So we need to fix it. EMILY FORTUNA: Yeah,
we can-- let's see. So if we look at a dismissible-- hover. So you can set the background,
secondary background, depending on which
direction you swipe. You set a color. MATT SULLIVAN: OK. So let's set the background
and secondary background. Again, we can use colors. And so we can put in a color. Now, we need to use
widgets, so we're going to put in a
container and we're going to color the
container for that. You could put in,
like, any widget. You could put in images. You could put in
whatever you feel like. We're just going to simply
do this with colors. So we're going to make
a background green. We're going to make secondary
background red, and boom. Dismissibles change state. We need to do a full restart. Oh, it costs us an
extra 200 milliseconds. We're so sad. And now, swiping left, you get
your green, and swiping right, you get your red. So we have Tinder
for restaurants. We've got a few minutes left. We want to-- we didn't
actually get much past this when we were planning
this, so let's see where we get to with this one. So we have dismissed
it, but we're not doing anything with the
data where we're dismissing. EMILY FORTUNA: Yeah. MATT SULLIVAN: So what can
we do with the dismissible? EMILY FORTUNA: I want to know-- I mean, color feedback is great,
but it would be nice to know-- get a little more
specific feedback of what these
swiping things mean. MATT SULLIVAN: You want to
have visual feedback on that. EMILY FORTUNA: Yeah. MATT SULLIVAN: OK. So the first thing we're
going to need to do is we're going to need
to detect the dismissed. And so we have this
handy on dismissed. And on dismissed, as far as I
remember, returns direction. And this-- we're going
to be able to go, is it a left or a
right direction? So we're going to be able to
check if that direction is-- so we're going to check
if the direction is equal to dismiss direction left
or dismiss direction right. What have we got? End to start. And what's the other one? OK, perfect. So we have we like
and we don't like, and we hope that they're
in the right direction. So if we then do, again, full-- EMILY FORTUNA: Oops. MATT SULLIVAN: A full restart. Uh-oh. There we go, and we
swipe in one direction. I like! Well, actually got it backwards. EMILY FORTUNA: At
the very bottom. MATT SULLIVAN: But
you know, that's fine. EMILY FORTUNA: OK, let's
actually see it, though. MATT SULLIVAN: OK, so we've
got a couple of minutes. Yeah, lets see where we
can get to with this. So why don't we show this
visually on the screen? And so handily, we're using-- this is wrapped in a
scaffold, and the scaffold gives us access to a snack bar. So what we can do is we can
pull up the scaffold object and we can show a snack bar. So, great. What we need now is
we need a widget which is going to be snack
bar widget, probably. EMILY FORTUNA: Oh, snack bar? MATT SULLIVAN: Because
we're showing snack bar. EMILY FORTUNA: Yes, my bad. MATT SULLIVAN: Well, we'll
add returns in in a minute. We'll make this look nice. It'll all be good. It'll all be good. So we go to snack bar, and a
snack bar is going to take-- EMILY FORTUNA: Content. MATT SULLIVAN: Yep. And we're going to
give that some text. And then we're going to-- EMILY FORTUNA: I think
I parentheses messed up. MATT SULLIVAN: We got
parentheses messed up. We can bounce these. One more. There we go. And so what happens
now when we do a full restart is going to
be we swipe left or right, and we're going to print. We swipe the other way, and-- EMILY FORTUNA: We have
it mixed up, but-- MATT SULLIVAN: Well, we've
gone off script enough that I think probably
a good place to stop. Do you think? EMILY FORTUNA: OK, OK, OK. MATT SULLIVAN: Oh,
we're going to do-- OK. There we go. EMILY FORTUNA: There we go. MATT SULLIVAN: There we go. [APPLAUSE] We're going to finish showing
you just a couple of things while we have a
couple of minutes. When you're building
these, there's a very handy overlay
for looking at how your widgets are rendered. We can just switch it on and
off and toggle it from the menu. You can see here
this is actually live overlaying on your
device or in the emulator, showing you where your padding
is and everything else. We haven't changed
our padding much, but this is really
handy when you're building your widgets
you want to work out exactly what's going on there. EMILY FORTUNA: Yeah, if
you have custom widgets-- since we used basically
all out-of-the-box stuff, we didn't adjust
padding or anything. But if you're doing custom
widgets and need to debug, this is your friend. Oops. Not that. MATT SULLIVAN: And then
the one other thing we'd like to show
you is performance. We want to take a look at
the performance overlay, and what this will give you,
like, as we scroll through or we interact with things-- this will give you, basically,
what your refresh rate is. You're hitting your
60 FPS or whatnot. At the moment, we're doing
pretty well with that because we've been using all
the stock standard widgets. But this is very handy. As you build out your app,
you can bring this up. You can play with
what you've built. You can see are you getting just
the performance that you need. A couple of handy tips there. I think we're good. We have Tinder for restaurants. All of this code-- actually, we lied because
there is one other slide. All of this code
is up on GitHub, and you can check it
out and it's evolving and we'll continue to
add to this over time. So-- EMILY FORTUNA: Oh, you can
also check that poll request where I tried to make a
slider to see the distance, depending on how far
you wanted to walk. But then I maxed out our
API requests per day. MATT SULLIVAN: Yeah. Bear in mind when
you use a slider and you have it directly
wired to your HTP request-- EMILY FORTUNA: You might
make a lot of requests if you're not
carefully writing it. MATT SULLIVAN: Emily destroyed
my quota in Google Cloud. Thank you very much. We had to wait 24
hours before we could start playing with it again. Thank you very
much for your time. It's been a pleasure. [APPLAUSE]