1 00:00:00,000 --> 00:00:02,946 [MUSIC PLAYING] 2 00:00:02,946 --> 00:00:16,132 3 00:00:16,132 --> 00:00:18,340 JORDAN HAYASHI: Hello, and welcome for lecture eight. 4 00:00:18,340 --> 00:00:20,470 Today we're joined by Charlie Cheever. 5 00:00:20,470 --> 00:00:22,270 Charlie did his undergrad at Harvard. 6 00:00:22,270 --> 00:00:28,900 He actually took CS50 back in the day and went on to join Facebook, 7 00:00:28,900 --> 00:00:33,490 later founded a website called Quora, and has now founded 8 00:00:33,490 --> 00:00:35,530 and leading the team over at Expo. 9 00:00:35,530 --> 00:00:40,330 So I will hand it over to him, and he will do a lecture on Expo components. 10 00:00:40,330 --> 00:00:41,724 So welcome Charlie. 11 00:00:41,724 --> 00:00:42,640 CHARLIE CHEEVER: Cool. 12 00:00:42,640 --> 00:00:43,390 Thanks, Jordan. 13 00:00:43,390 --> 00:00:46,401 And thanks for having me here. 14 00:00:46,401 --> 00:00:46,900 Cool. 15 00:00:46,900 --> 00:00:49,480 So I'm Charlie. 16 00:00:49,480 --> 00:00:52,855 And I'm gonna talk to you about Expo today. 17 00:00:52,855 --> 00:00:54,730 I think most people in this class are already 18 00:00:54,730 --> 00:00:57,580 using it to build a lot of their projects and assignments 19 00:00:57,580 --> 00:00:58,671 for this class. 20 00:00:58,671 --> 00:01:00,670 So I'll talk a little bit more about what it is, 21 00:01:00,670 --> 00:01:03,220 and then go into some detail about different parts of it 22 00:01:03,220 --> 00:01:06,460 that you can use that you might not have encountered yet. 23 00:01:06,460 --> 00:01:08,530 So what is Expo? 24 00:01:08,530 --> 00:01:11,960 Expo's basically two things. 25 00:01:11,960 --> 00:01:17,230 One is it's like a project and an effort that is basically 26 00:01:17,230 --> 00:01:19,630 trying to take the spirit of the web and the ideas 27 00:01:19,630 --> 00:01:25,970 of the web and the accessibility and the distribution power and things like that 28 00:01:25,970 --> 00:01:30,580 and fuse it with the sort of functionality 29 00:01:30,580 --> 00:01:34,000 and gestures and animations and capabilities 30 00:01:34,000 --> 00:01:36,610 and look and feel that you get with native mobile apps 31 00:01:36,610 --> 00:01:38,800 that people like using on their phones. 32 00:01:38,800 --> 00:01:41,004 Because people used to use the web. 33 00:01:41,004 --> 00:01:43,420 And there are lots of people that can develop for the web. 34 00:01:43,420 --> 00:01:46,378 And that's probably the most popular development platform in the world. 35 00:01:46,378 --> 00:01:48,160 But it's really hard to develop for mobile 36 00:01:48,160 --> 00:01:50,868 even though everyone in the world is carrying around their phones 37 00:01:50,868 --> 00:01:52,620 all the time now. 38 00:01:52,620 --> 00:01:56,950 And so then as part of that, what Expo is secondly 39 00:01:56,950 --> 00:02:01,630 is basically like a standard library of components 40 00:02:01,630 --> 00:02:05,230 that let you access basically everything on your phone device 41 00:02:05,230 --> 00:02:09,130 through JavaScript without having to worry about Xcode or Android 42 00:02:09,130 --> 00:02:10,545 Studio or libraries like that. 43 00:02:10,545 --> 00:02:13,420 And so when I say access everything on your phone through JavaScript, 44 00:02:13,420 --> 00:02:16,210 I mean basically all the hardware peripherals 45 00:02:16,210 --> 00:02:20,440 like accelerometer, gyroscope, GPS location, 46 00:02:20,440 --> 00:02:23,650 pushing notification, things like that, along with stuff on the screen, 47 00:02:23,650 --> 00:02:27,490 like native maps, native video player, sound, those kind of things, 48 00:02:27,490 --> 00:02:30,934 camera, and then some common libraries that people 49 00:02:30,934 --> 00:02:33,850 need to use a lot of the time, like Facebook login, Google login, ads, 50 00:02:33,850 --> 00:02:35,390 things like that. 51 00:02:35,390 --> 00:02:38,620 So there's actually a ton of these things. 52 00:02:38,620 --> 00:02:44,490 You can see a whole list if you go to docs.expo.io. 53 00:02:44,490 --> 00:02:49,760 I'm going to go there, like, every 45 seconds, probably, during this lecture. 54 00:02:49,760 --> 00:02:51,797 So just familiar with these. 55 00:02:51,797 --> 00:02:54,130 And if you just scroll down on the left side right here, 56 00:02:54,130 --> 00:02:58,420 you can see a full list where accelerometer, AdMob, amplitude, 57 00:02:58,420 --> 00:03:00,880 uploading-- all of these things are available. 58 00:03:00,880 --> 00:03:03,530 I'm only going to have time to show you some of them. 59 00:03:03,530 --> 00:03:07,450 But they all work pretty well, and they're all tested. 60 00:03:07,450 --> 00:03:10,240 And so basically, everything here is a combination 61 00:03:10,240 --> 00:03:13,000 of things that we've made at Expo as part of the project, 62 00:03:13,000 --> 00:03:17,554 along with editorially selecting some of the best open-source things 63 00:03:17,554 --> 00:03:20,470 out in the community, like vector icons, which is the most popular way 64 00:03:20,470 --> 00:03:24,730 to do icons in React Native, and React Native Maps, which originally 65 00:03:24,730 --> 00:03:27,811 was made at Airbnb, I think by this guy Leland Richardson, 66 00:03:27,811 --> 00:03:30,310 which is kind of universally the way that everyone does maps 67 00:03:30,310 --> 00:03:31,150 with React Native. 68 00:03:31,150 --> 00:03:32,890 So we've pulled in a few of those open-source projects 69 00:03:32,890 --> 00:03:35,015 that are best of breed and that are kept up to date 70 00:03:35,015 --> 00:03:37,210 and maintained, and then built the things that there 71 00:03:37,210 --> 00:03:39,970 wasn't a great solution already. 72 00:03:39,970 --> 00:03:42,550 And so we're going to be using the Expo client on our phones. 73 00:03:42,550 --> 00:03:46,090 And we're going to use Snack a lot, which is at snack.expo.io. 74 00:03:46,090 --> 00:03:52,310 And also, we're going to use XDE, the sort of desktop development tool. 75 00:03:52,310 --> 00:03:56,710 And I tend to use VS Code for my editor. 76 00:03:56,710 --> 00:04:01,390 So the first thing we're going to dive into is maps and location. 77 00:04:01,390 --> 00:04:04,960 I'm just gonna build a really simple demo of using maps, and then throwing 78 00:04:04,960 --> 00:04:10,400 a couple of pins on it and showing where we are and stuff like that. 79 00:04:10,400 --> 00:04:17,339 So to do this, I'm gonna go into Snack, which you can get to at snack.expo.io. 80 00:04:17,339 --> 00:04:20,399 And this is just basically the default project. 81 00:04:20,399 --> 00:04:22,597 I made a few changes here. 82 00:04:22,597 --> 00:04:25,430 I'll just start from scratch so people can follow along more easily. 83 00:04:25,430 --> 00:04:28,540 I'm going to reload this. 84 00:04:28,540 --> 00:04:33,400 And I'm going to change this constants thing here to just import Expo. 85 00:04:33,400 --> 00:04:37,210 I'm going to delete this import asset example and import 86 00:04:37,210 --> 00:04:39,110 card because we don't need those. 87 00:04:39,110 --> 00:04:41,770 And then I'm just going to delete all this stuff in here, 88 00:04:41,770 --> 00:04:45,914 and then change this to expo.constants. 89 00:04:45,914 --> 00:04:47,330 So now I just have the plain view. 90 00:04:47,330 --> 00:04:49,204 So I'm not even going to use that plain view. 91 00:04:49,204 --> 00:04:54,400 I'm actually just going to do expo.mapview. 92 00:04:54,400 --> 00:04:58,270 And then I'm going to do run device so I can 93 00:04:58,270 --> 00:04:59,900 take a look at this thing on my phone. 94 00:04:59,900 --> 00:05:03,508 95 00:05:03,508 --> 00:05:05,000 So I'm opening this up. 96 00:05:05,000 --> 00:05:07,200 I'm using an iPhone so I can mirror it here. 97 00:05:07,200 --> 00:05:11,084 And so here's what this looks like now. 98 00:05:11,084 --> 00:05:12,500 It just looks like a white screen. 99 00:05:12,500 --> 00:05:15,140 100 00:05:15,140 --> 00:05:17,090 So I will try, actually-- 101 00:05:17,090 --> 00:05:25,430 I'm going to get rid of files, and I'm gonna shrink this a little bit 102 00:05:25,430 --> 00:05:28,460 and try to move this over here. 103 00:05:28,460 --> 00:05:31,590 Maybe we'll be able to see it then. 104 00:05:31,590 --> 00:05:32,880 OK, there we go. 105 00:05:32,880 --> 00:05:35,040 Now we can see both at the same time. 106 00:05:35,040 --> 00:05:38,570 So part of why this map view isn't showing up is that it's too small, 107 00:05:38,570 --> 00:05:42,440 and it's sort of just not showing up because it's not big enough. 108 00:05:42,440 --> 00:05:45,290 So we'll say flex one under style. 109 00:05:45,290 --> 00:05:48,650 And then now, bam, a map view appears. 110 00:05:48,650 --> 00:05:50,150 And it's taking up the whole screen. 111 00:05:50,150 --> 00:05:52,310 That's kind of what we want. 112 00:05:52,310 --> 00:05:56,180 So one sidenote here is this is an Apple map because I'm using an iPhone. 113 00:05:56,180 --> 00:05:58,700 On an Android phone, this would be a Google map. 114 00:05:58,700 --> 00:06:00,802 But Google Maps is also available for iPhone. 115 00:06:00,802 --> 00:06:02,760 And so you can switch the provider if you want. 116 00:06:02,760 --> 00:06:12,590 So I can say provider equals expo.mapview.provider_google, 117 00:06:12,590 --> 00:06:16,670 and now this is using a Google map. 118 00:06:16,670 --> 00:06:18,950 And you can see it says Google in the corner. 119 00:06:18,950 --> 00:06:24,110 And Google Maps default to, I think, somewhere in the UK, like, 120 00:06:24,110 --> 00:06:26,430 probably Greenwich meridian or something like that. 121 00:06:26,430 --> 00:06:28,782 Whereas at Apple Maps defaults to the United States. 122 00:06:28,782 --> 00:06:30,740 We'll use Apple Maps for the rest of this demo, 123 00:06:30,740 --> 00:06:33,560 but you can switch between them pretty easily. 124 00:06:33,560 --> 00:06:36,560 So I'm gonna take a look at the maps documentation 125 00:06:36,560 --> 00:06:40,530 here, just so we have a good reference point to start. 126 00:06:40,530 --> 00:06:44,900 And if you look here, you can see the first thing 127 00:06:44,900 --> 00:06:46,210 it shows is a simple example. 128 00:06:46,210 --> 00:06:48,085 And I have a way to set initial region, which 129 00:06:48,085 --> 00:06:51,210 should be pretty useful because looking at a giant map of the United States 130 00:06:51,210 --> 00:06:53,080 isn't that interesting in a lot of cases. 131 00:06:53,080 --> 00:06:58,190 So I'm just going to copy this and bring it over here and paste it in here. 132 00:06:58,190 --> 00:07:02,460 And now you can see this makes this initial region in San Francisco. 133 00:07:02,460 --> 00:07:05,870 Some of you might be in San Francisco if you're watching on stream. 134 00:07:05,870 --> 00:07:07,790 But we're actually in Cambridge right now. 135 00:07:07,790 --> 00:07:13,650 So it'd be great if we could center the map there or wherever we actually are. 136 00:07:13,650 --> 00:07:16,190 And so what I'm gonna do is actually use the location 137 00:07:16,190 --> 00:07:20,930 API to figure out where we are, and then center the map on that. 138 00:07:20,930 --> 00:07:25,310 And so what we're gonna do is slip over to the documentation 139 00:07:25,310 --> 00:07:27,410 and take a look at location. 140 00:07:27,410 --> 00:07:29,609 141 00:07:29,609 --> 00:07:31,400 You can see the first thing it says here is 142 00:07:31,400 --> 00:07:38,060 that you need to use the permissions API to get permission to ask for location. 143 00:07:38,060 --> 00:07:41,060 If you're used to using an app on your phone that asks for a location, 144 00:07:41,060 --> 00:07:43,268 you probably have seen these dialogs pop up that say, 145 00:07:43,268 --> 00:07:47,000 like, Facebook Messenger would like to use your location. 146 00:07:47,000 --> 00:07:48,980 OK or cancel. 147 00:07:48,980 --> 00:07:52,640 And you kind of only get one shot as an app to ask for that permission. 148 00:07:52,640 --> 00:07:57,590 So a lot of apps will, like, pre-ask you and ask for permission 149 00:07:57,590 --> 00:07:59,450 to ask permission for your location. 150 00:07:59,450 --> 00:08:02,180 And then if you don't say OK, they won't ask you 151 00:08:02,180 --> 00:08:04,961 because they don't want to use their one chance. 152 00:08:04,961 --> 00:08:06,710 In the Expo client app here, I've actually 153 00:08:06,710 --> 00:08:08,000 already asked for location permission. 154 00:08:08,000 --> 00:08:08,940 It's been granted. 155 00:08:08,940 --> 00:08:10,700 So we won't see the dialog pop up. 156 00:08:10,700 --> 00:08:12,980 But if it was the first time, or if you're 157 00:08:12,980 --> 00:08:15,350 in, like, a standalone app or something like that, 158 00:08:15,350 --> 00:08:16,724 we do want to ask for permission. 159 00:08:16,724 --> 00:08:18,241 So we'll cover that here. 160 00:08:18,241 --> 00:08:20,240 And asking for permission, again, using the Expo 161 00:08:20,240 --> 00:08:23,120 permissions API is fine because it'll just say, 162 00:08:23,120 --> 00:08:25,610 oh, you already have permission, and it's granted. 163 00:08:25,610 --> 00:08:29,360 So I'm gonna write a little method here that's called 164 00:08:29,360 --> 00:08:31,415 askForLocationPermissionAsync. 165 00:08:31,415 --> 00:08:37,580 166 00:08:37,580 --> 00:08:42,740 Or I'm gonna just call this, like, getLocationAsync. 167 00:08:42,740 --> 00:08:45,270 So I'm gonna ask for permission first. 168 00:08:45,270 --> 00:08:52,290 So the first thing I'm gonna do is say let status equals await. 169 00:08:52,290 --> 00:09:01,432 expo.permissions.ask async expo.permissions.location. 170 00:09:01,432 --> 00:09:03,140 I can see a list of all the permissions I 171 00:09:03,140 --> 00:09:08,220 can ask for if I go to the permissions page on the Expo docs. 172 00:09:08,220 --> 00:09:10,640 You can see here's this Expo permissions get async. 173 00:09:10,640 --> 00:09:12,570 And then type is the argument it takes. 174 00:09:12,570 --> 00:09:13,737 It's just a string. 175 00:09:13,737 --> 00:09:16,070 And you can see a complete list if you scroll down here. 176 00:09:16,070 --> 00:09:18,830 So location, camera, audio recording, contacts, et cetera, et cetera, 177 00:09:18,830 --> 00:09:19,400 et cetera. 178 00:09:19,400 --> 00:09:23,240 The one we're interested in here is expo.permissions.location 179 00:09:23,240 --> 00:09:25,190 because we're going to ask for location. 180 00:09:25,190 --> 00:09:26,109 So that's right. 181 00:09:26,109 --> 00:09:28,400 But one thing I made as a mistake is that this actually 182 00:09:28,400 --> 00:09:30,941 needs to be an async function because we want to await stuff. 183 00:09:30,941 --> 00:09:34,940 So I'm gonna say equals async, and then make it an arrow function. 184 00:09:34,940 --> 00:09:38,050 This is a good way to make async functions as class methods, 185 00:09:38,050 --> 00:09:41,870 or as instance methods in your classes. 186 00:09:41,870 --> 00:09:43,522 So now we need to check the status. 187 00:09:43,522 --> 00:09:45,230 The typical pattern with Expo permissions 188 00:09:45,230 --> 00:09:47,240 API is basically to ask for permission, and then 189 00:09:47,240 --> 00:09:53,910 say if status doesn't equal granted, then sort of log an error or show 190 00:09:53,910 --> 00:09:54,500 an error. 191 00:09:54,500 --> 00:09:58,470 192 00:09:58,470 --> 00:10:00,060 And here we'll just return. 193 00:10:00,060 --> 00:10:03,060 But in a more fully-featured application, 194 00:10:03,060 --> 00:10:05,149 you might want to show an error message or force 195 00:10:05,149 --> 00:10:06,690 the user to another flow or whatever. 196 00:10:06,690 --> 00:10:10,420 Here we'll just jump out and not do anything. 197 00:10:10,420 --> 00:10:12,550 And then the next thing we'll do is we'll say, 198 00:10:12,550 --> 00:10:14,330 OK, we're going to ask for the location. 199 00:10:14,330 --> 00:10:18,630 So I can go back to the location page in the docs. 200 00:10:18,630 --> 00:10:24,420 And I can see that the way we do this is we 201 00:10:24,420 --> 00:10:28,110 use location get current position async. 202 00:10:28,110 --> 00:10:31,020 And this takes bracket bracket as an argument. 203 00:10:31,020 --> 00:10:33,660 So let's figure out what that means. 204 00:10:33,660 --> 00:10:34,770 This is an options array. 205 00:10:34,770 --> 00:10:38,769 And it can take enable high accuracy or maximum age. 206 00:10:38,769 --> 00:10:40,560 We don't really need to do anything special 207 00:10:40,560 --> 00:10:44,480 because we're just trying to get generally what location we're in. 208 00:10:44,480 --> 00:10:46,480 And so we're just not going to give any options. 209 00:10:46,480 --> 00:10:51,470 But I think that it requires giving the options thing as an empty object. 210 00:10:51,470 --> 00:10:54,524 Enable high accuracy is nice because it gives you higher accuracy. 211 00:10:54,524 --> 00:10:56,190 But it also uses more battery on phones. 212 00:10:56,190 --> 00:10:57,939 So unless you actually need that accuracy, 213 00:10:57,939 --> 00:10:59,770 you generally shouldn't use it. 214 00:10:59,770 --> 00:11:06,630 So what we'll say here is say let location equals await expo.location get 215 00:11:06,630 --> 00:11:11,230 current position async, I think it was. 216 00:11:11,230 --> 00:11:15,480 And then so now, if this happens, we should get a location. 217 00:11:15,480 --> 00:11:19,590 So I'm going log it as soon as I get it. 218 00:11:19,590 --> 00:11:23,520 That way, we can sort of inspect what we get. 219 00:11:23,520 --> 00:11:25,670 So for that to happen, I need to call this. 220 00:11:25,670 --> 00:11:29,880 So what I'm going to do is I'm going to say on component did mount, 221 00:11:29,880 --> 00:11:32,820 which is a React lifecycle method that you're probably familiar with, 222 00:11:32,820 --> 00:11:36,240 I'm going to say this.getLocationAsync. 223 00:11:36,240 --> 00:11:40,770 So this will call this method as soon as the component mounts. 224 00:11:40,770 --> 00:11:43,780 Oh, since I changed this and the Snack reloaded, it's already done this. 225 00:11:43,780 --> 00:11:48,610 So now I can see this object here has a time stamp, 226 00:11:48,610 --> 00:11:50,770 and then it also has coords. 227 00:11:50,770 --> 00:11:55,440 And inside coords is a latitude, an altitude, a longitude, a heading, 228 00:11:55,440 --> 00:12:01,390 an accuracy, an altitude accuracy estimate, and a speed estimate. 229 00:12:01,390 --> 00:12:04,390 Since we're not moving at all, it doesn't have any concept of our speed. 230 00:12:04,390 --> 00:12:05,910 So it says speed negative 1. 231 00:12:05,910 --> 00:12:11,057 And since we're not moving at all, heading is also negative 1, 232 00:12:11,057 --> 00:12:12,390 which is sort of an error value. 233 00:12:12,390 --> 00:12:14,910 234 00:12:14,910 --> 00:12:18,510 And so what we're going to do is use those coords from that object to, like, 235 00:12:18,510 --> 00:12:21,000 populate the initial place of our map. 236 00:12:21,000 --> 00:12:25,230 But the thing is in our render method, right now we're rendering the map view, 237 00:12:25,230 --> 00:12:27,450 and we're sticking in the initial region right away. 238 00:12:27,450 --> 00:12:30,300 But we don't get the location until shortly afterwards when 239 00:12:30,300 --> 00:12:33,030 we're able to have component did mount fire, 240 00:12:33,030 --> 00:12:35,410 and then we check the permissions, which is asynchronous. 241 00:12:35,410 --> 00:12:37,650 And then we ask the GPS for the location. 242 00:12:37,650 --> 00:12:39,750 And then we pull this information out. 243 00:12:39,750 --> 00:12:42,450 So we aren't quite ready right off the bat 244 00:12:42,450 --> 00:12:46,110 when the application starts to show the map with an initial location 245 00:12:46,110 --> 00:12:46,990 where we are. 246 00:12:46,990 --> 00:12:52,010 So we're going to have to do something using state to make that work. 247 00:12:52,010 --> 00:12:57,030 So we're going to say state location null to start. 248 00:12:57,030 --> 00:13:01,710 I'm just adding this as an original initial way to set state. 249 00:13:01,710 --> 00:13:09,720 And then here, instead of logging the location, what I'll do is I'll say, 250 00:13:09,720 --> 00:13:14,430 this.setState location. 251 00:13:14,430 --> 00:13:16,320 If you're not familiar with this syntax here, 252 00:13:16,320 --> 00:13:21,690 this is just a shorthand for saying location, colon, location. 253 00:13:21,690 --> 00:13:26,502 I'll use that a couple of times because it's a pretty convenient shorthand. 254 00:13:26,502 --> 00:13:29,710 This little brackets button that says prettier in the lower right-hand corner 255 00:13:29,710 --> 00:13:32,620 that I keep hitting, it just reformats the code so it's easier to read. 256 00:13:32,620 --> 00:13:34,911 And when I make indenting mistakes and stuff like that, 257 00:13:34,911 --> 00:13:36,640 it takes care of those. 258 00:13:36,640 --> 00:13:40,950 So now, when this component mounts, it should call get location async. 259 00:13:40,950 --> 00:13:47,490 And that should set a state once it's ready to be an actual location. 260 00:13:47,490 --> 00:13:48,990 So now I don't want to show the map. 261 00:13:48,990 --> 00:13:52,110 I'm just gonna show a blank screen until we have the location ready. 262 00:13:52,110 --> 00:13:56,310 So what I'm gonna do here in the render method is say if this.state.isReady-- 263 00:13:56,310 --> 00:14:00,131 264 00:14:00,131 --> 00:14:01,630 actually, I'm not gonna use isReady. 265 00:14:01,630 --> 00:14:03,720 I'm gonna say location-- 266 00:14:03,720 --> 00:14:09,390 if no location, then return an empty view. 267 00:14:09,390 --> 00:14:13,630 Otherwise, we'll have a location that we can populate. 268 00:14:13,630 --> 00:14:18,450 So that means if the code makes it down to this part, this.state.location, 269 00:14:18,450 --> 00:14:20,880 has a value in it that will have coords. 270 00:14:20,880 --> 00:14:23,520 So I'll say this.state.location.coords.latitude. 271 00:14:23,520 --> 00:14:26,790 272 00:14:26,790 --> 00:14:30,560 And then now you can see this already updated. 273 00:14:30,560 --> 00:14:33,780 Now that I've changed the latitude but not the longitude, 274 00:14:33,780 --> 00:14:36,258 I'm on some highway in the middle of America somewhere. 275 00:14:36,258 --> 00:14:38,133 Let's zoom out and see exactly where that is. 276 00:14:38,133 --> 00:14:41,031 277 00:14:41,031 --> 00:14:42,220 Looks like Oregon. 278 00:14:42,220 --> 00:14:44,640 So the north-south is now correct, but I need 279 00:14:44,640 --> 00:14:48,120 to change the longitude to move it over to Cambridge, where we are. 280 00:14:48,120 --> 00:14:51,525 So I'll just change that to this.state.location.coords.longitude. 281 00:14:51,525 --> 00:14:54,750 282 00:14:54,750 --> 00:14:59,670 And now you can see the map now centered on Cambridge, which is pretty 283 00:14:59,670 --> 00:15:02,240 cool, because that's where we are. 284 00:15:02,240 --> 00:15:06,270 And if you're following along and you did this in Bulgaria or something, 285 00:15:06,270 --> 00:15:08,340 the map should be centered on Bulgaria for you, 286 00:15:08,340 --> 00:15:10,796 as long as your GPS is working. 287 00:15:10,796 --> 00:15:12,670 So it's normal if you see something different 288 00:15:12,670 --> 00:15:14,610 if you're not in the same place. 289 00:15:14,610 --> 00:15:15,120 Cool. 290 00:15:15,120 --> 00:15:18,000 So this is cool that this map is centered on us. 291 00:15:18,000 --> 00:15:20,235 But I think a lot of times when you really 292 00:15:20,235 --> 00:15:23,110 want to get your bearings on a map, you want to have a pin that says, 293 00:15:23,110 --> 00:15:24,130 hey, you're here. 294 00:15:24,130 --> 00:15:28,670 So let's add a marker to this map that shows where we are. 295 00:15:28,670 --> 00:15:29,950 Clear these logs. 296 00:15:29,950 --> 00:15:31,560 Shrink this down a little bit. 297 00:15:31,560 --> 00:15:37,720 So if I go look at the maps documentation, 298 00:15:37,720 --> 00:15:41,010 you can see this is built by Airbnb. 299 00:15:41,010 --> 00:15:45,120 And so the documentation basically says, for full documentation 300 00:15:45,120 --> 00:15:46,950 go check out Airbnb React native maps. 301 00:15:46,950 --> 00:15:49,890 So let's go over there. 302 00:15:49,890 --> 00:15:52,770 And then under component API, you can see 303 00:15:52,770 --> 00:15:55,020 it has map view, which we already are using, 304 00:15:55,020 --> 00:15:58,569 marker, callout, polygon, polyline, circle, and overlay. 305 00:15:58,569 --> 00:16:01,860 Some of these are pretty fancy and would take a long time to go into detail on. 306 00:16:01,860 --> 00:16:03,280 But marker's really simple. 307 00:16:03,280 --> 00:16:05,279 So let's just start putting a marker on the map. 308 00:16:05,279 --> 00:16:07,560 309 00:16:07,560 --> 00:16:12,480 You can see this isn't too complicated. 310 00:16:12,480 --> 00:16:15,750 It basically just has a whole bunch of props you can add, 311 00:16:15,750 --> 00:16:18,420 and then some things you can call on it. 312 00:16:18,420 --> 00:16:21,690 We'll just use the most simple props in general, 313 00:16:21,690 --> 00:16:26,814 which are sort of title, description, pin color, and coordinate. 314 00:16:26,814 --> 00:16:29,130 Coordinate is how we'll set where the marker is, 315 00:16:29,130 --> 00:16:31,170 and then pin color is self-explanatory. 316 00:16:31,170 --> 00:16:35,190 And then title and description, I'll show you how they show up. 317 00:16:35,190 --> 00:16:37,980 So it's pretty easy to put a marker on the map. 318 00:16:37,980 --> 00:16:41,370 You just make-- instead of the map view being sort of a singleton component, 319 00:16:41,370 --> 00:16:44,590 you just make it a component that has things inside of it. 320 00:16:44,590 --> 00:16:46,590 And then we'll say expo.Mapview.Marker. 321 00:16:46,590 --> 00:16:50,385 322 00:16:50,385 --> 00:16:53,010 Now we need to give a coordinate for the marker so it shows up. 323 00:16:53,010 --> 00:16:59,025 So we'll say coordinate equals this.state.location.coords. 324 00:16:59,025 --> 00:17:01,940 325 00:17:01,940 --> 00:17:06,270 Coordinate just requires latitude and longitude, but this object has those. 326 00:17:06,270 --> 00:17:08,859 So it's OK that has other things, as well. 327 00:17:08,859 --> 00:17:12,540 So now you can see over here we have a dot right 328 00:17:12,540 --> 00:17:14,160 in the center of the map where we are. 329 00:17:14,160 --> 00:17:16,050 That's pretty cool. 330 00:17:16,050 --> 00:17:18,119 If I zoom in, it's right there. 331 00:17:18,119 --> 00:17:23,399 And you can sort of see we're actually at Radcliffe College, which is actually 332 00:17:23,399 --> 00:17:23,940 where we are. 333 00:17:23,940 --> 00:17:26,130 Pretty cool. 334 00:17:26,130 --> 00:17:29,620 So now we might want to say what that means. 335 00:17:29,620 --> 00:17:34,980 So we'll sort of say title equals you are here. 336 00:17:34,980 --> 00:17:36,010 OK, cool. 337 00:17:36,010 --> 00:17:38,760 So now, after that reloads, when I tap on that marker, 338 00:17:38,760 --> 00:17:43,710 it now says, you are here, which is pretty useful. 339 00:17:43,710 --> 00:17:45,240 This is somewhat useful to know. 340 00:17:45,240 --> 00:17:50,130 But we might also want to have some other things on the map. 341 00:17:50,130 --> 00:17:54,930 So when I went to school here, I lived in a dorm called Eliot House. 342 00:17:54,930 --> 00:17:58,740 And so it would be kind of cool to be able to put that on this map. 343 00:17:58,740 --> 00:18:03,400 And so there probably is a way to do that. 344 00:18:03,400 --> 00:18:10,650 So I know that the address of Eliot house is, like, 101 Dunster Street. 345 00:18:10,650 --> 00:18:14,550 But I don't really know how to put a map view at 101 Dunster 346 00:18:14,550 --> 00:18:18,469 Street because if you look at the map marker API, 347 00:18:18,469 --> 00:18:20,760 it takes a coordinate, which is latitude and longitude. 348 00:18:20,760 --> 00:18:25,680 And so we need some way to go from an address to the latitude and longitude. 349 00:18:25,680 --> 00:18:28,950 And what we can use for that is this Expo API under location 350 00:18:28,950 --> 00:18:30,630 called geocoding. 351 00:18:30,630 --> 00:18:34,500 So if you go to location in the docs and you scroll down a little bit, 352 00:18:34,500 --> 00:18:37,110 after the stuff about getting position, there's 353 00:18:37,110 --> 00:18:44,370 something called geocode async, which takes an address as a string 354 00:18:44,370 --> 00:18:49,500 and then will return some guesses at the lat-long based on where you are 355 00:18:49,500 --> 00:18:52,571 and how popular different places are and things like that. 356 00:18:52,571 --> 00:18:54,570 So we can try just putting in 101 Dunster Street 357 00:18:54,570 --> 00:18:57,150 and seeing if that works. 358 00:18:57,150 --> 00:19:00,060 So I'll do that here. 359 00:19:00,060 --> 00:19:06,120 So while we're getting location, once we do 360 00:19:06,120 --> 00:19:11,100 that, I'm going to actually ask here for the place information, as well. 361 00:19:11,100 --> 00:19:18,540 So I'm going to say let Eliot House equal away 362 00:19:18,540 --> 00:19:27,600 expo.location.geocodeAsync 101 Dunster Street. 363 00:19:27,600 --> 00:19:30,190 364 00:19:30,190 --> 00:19:35,904 Now I'm just gonna log this, just so we can see what we get back. 365 00:19:35,904 --> 00:19:38,820 Let me see if I have other log statements that are getting in the way. 366 00:19:38,820 --> 00:19:50,532 367 00:19:50,532 --> 00:19:51,530 No. 368 00:19:51,530 --> 00:19:52,452 Looks like I don't. 369 00:19:52,452 --> 00:19:53,660 So I can see what I get back. 370 00:19:53,660 --> 00:19:56,300 Here is an array. 371 00:19:56,300 --> 00:20:02,960 And the first element has a latitude and a longitude and accuracy. 372 00:20:02,960 --> 00:20:11,059 So that is-- oh, that's actually something else. 373 00:20:11,059 --> 00:20:11,850 Let me clear these. 374 00:20:11,850 --> 00:20:15,690 375 00:20:15,690 --> 00:20:21,440 So now if I do that-- 376 00:20:21,440 --> 00:20:22,731 am I doing this wrong? 377 00:20:22,731 --> 00:20:26,030 378 00:20:26,030 --> 00:20:27,140 No, it's not. 379 00:20:27,140 --> 00:20:33,530 So the latitude and longitude of this Eliot House is 42.3707463. 380 00:20:33,530 --> 00:20:37,880 And the longitude is negative 71.1209627. 381 00:20:37,880 --> 00:20:41,480 So now we have to pull this out of being the first element of the array 382 00:20:41,480 --> 00:20:46,040 and somehow put it in a marker on the map. 383 00:20:46,040 --> 00:20:49,390 So I'm going to do this-- 384 00:20:49,390 --> 00:20:51,710 use parentheses here, and then take the zero index. 385 00:20:51,710 --> 00:20:56,600 So now when I scroll down, now there's no array wrapping this, 386 00:20:56,600 --> 00:21:00,260 and it's just a raw object that has a latitude and a longitude. 387 00:21:00,260 --> 00:21:02,060 And I'll add some other places, too. 388 00:21:02,060 --> 00:21:08,210 So I'll say The Crimson, which is the student newspaper, 389 00:21:08,210 --> 00:21:12,930 is at 14 Plympton Street, I think. 390 00:21:12,930 --> 00:21:23,310 And then [? Kitty ?] is at 2 Holyoke Place. 391 00:21:23,310 --> 00:21:26,600 392 00:21:26,600 --> 00:21:31,460 So then I'm gonna set places in state also. 393 00:21:31,460 --> 00:21:37,670 So I'll just say Eliot House, The Crimson, and Kitty. 394 00:21:37,670 --> 00:21:41,194 So now if I do prettier here, that should work. 395 00:21:41,194 --> 00:21:43,610 And so now I should be able to put additional markers here 396 00:21:43,610 --> 00:21:45,450 for those places. 397 00:21:45,450 --> 00:21:53,900 Map view, marker, coordinate equals this.state.places.EliotHouse. 398 00:21:53,900 --> 00:21:58,010 Title equals Eliot House. 399 00:21:58,010 --> 00:22:01,670 Description equals Domus. 400 00:22:01,670 --> 00:22:05,220 401 00:22:05,220 --> 00:22:09,440 So now I can see here's where we are. 402 00:22:09,440 --> 00:22:10,660 You are here. 403 00:22:10,660 --> 00:22:12,395 And then I can also see Elliott House. 404 00:22:12,395 --> 00:22:13,020 There is Domus. 405 00:22:13,020 --> 00:22:15,967 So to make this map look a little clearer, 406 00:22:15,967 --> 00:22:17,550 I'm gonna actually make this pin blue. 407 00:22:17,550 --> 00:22:20,720 408 00:22:20,720 --> 00:22:23,570 And so now, Eliot House is more clearly marked. 409 00:22:23,570 --> 00:22:26,660 And then I'll mark the other spots on the map, as well. 410 00:22:26,660 --> 00:22:28,590 Since this is pretty much the same thing, 411 00:22:28,590 --> 00:22:33,260 I'm just going to copy paste this and change the appropriate stuff. 412 00:22:33,260 --> 00:22:41,300 So this is going to be The Crimson, pin color crimson. 413 00:22:41,300 --> 00:22:43,290 I wonder if that works. 414 00:22:43,290 --> 00:23:00,370 And I'll make the coordinate of where we are be yellow just so that stands out. 415 00:23:00,370 --> 00:23:00,880 OK. 416 00:23:00,880 --> 00:23:01,880 Wow, that's hard to see. 417 00:23:01,880 --> 00:23:04,341 We'll use green instead for where we are. 418 00:23:04,341 --> 00:23:04,840 Cool. 419 00:23:04,840 --> 00:23:07,720 420 00:23:07,720 --> 00:23:13,240 So now as long as I change these-- 421 00:23:13,240 --> 00:23:17,500 crimson, student newspaper. 422 00:23:17,500 --> 00:23:28,701 423 00:23:28,701 --> 00:23:30,450 Now I have a couple different places here. 424 00:23:30,450 --> 00:23:33,630 425 00:23:33,630 --> 00:23:36,300 And if I zoom in, it'll show me the description of all of them 426 00:23:36,300 --> 00:23:37,350 as I tap them. 427 00:23:37,350 --> 00:23:39,390 And I can also see where I am. 428 00:23:39,390 --> 00:23:41,940 Since when I changed this code and it zooms back 429 00:23:41,940 --> 00:23:45,270 to the original zoom distance, all these things 430 00:23:45,270 --> 00:23:48,090 are kind of clustered in the center, and I'm zoomed out too far, 431 00:23:48,090 --> 00:23:50,980 I actually want to make the map zoomed in a little more by default. 432 00:23:50,980 --> 00:23:55,050 So I'm going to change this latitude delta and longitude delta a little bit. 433 00:23:55,050 --> 00:23:57,880 These values that I copied from the example are pretty reasonable. 434 00:23:57,880 --> 00:23:59,230 But they're just a little bit too big. 435 00:23:59,230 --> 00:24:01,271 So you want to zoom in about, like, maybe double. 436 00:24:01,271 --> 00:24:06,070 So I'm gonna do divided by 2 for both of these and see what happens. 437 00:24:06,070 --> 00:24:08,310 So now it's zoomed in a bit more. 438 00:24:08,310 --> 00:24:13,085 Let me see what happens if I do 3, if that looks better or worse. 439 00:24:13,085 --> 00:24:15,210 That looks a little better, but now these buildings 440 00:24:15,210 --> 00:24:18,390 are so close to the edge that we might want to not be quite that much. 441 00:24:18,390 --> 00:24:23,130 Let's just do 2.5. 442 00:24:23,130 --> 00:24:24,826 OK, that looks pretty good to me. 443 00:24:24,826 --> 00:24:27,492 That way I don't have to keep zooming in every time I make this. 444 00:24:27,492 --> 00:24:31,400 445 00:24:31,400 --> 00:24:33,410 So then the last thing I'll do is we might 446 00:24:33,410 --> 00:24:39,650 want to know where we are instead of just saying we're here or whatever. 447 00:24:39,650 --> 00:24:44,180 So I can actually use an API called reverse geocoding to take coordinates 448 00:24:44,180 --> 00:24:48,390 and turn them into an address or something like that. 449 00:24:48,390 --> 00:24:54,640 So what I'll do is I'll say let where equal 450 00:24:54,640 --> 00:25:11,010 await expo.location.reverseGeocode async location.coords. 451 00:25:11,010 --> 00:25:13,965 So this is going to find the coordinates of where we are and then do 452 00:25:13,965 --> 00:25:16,680 a reverse geocode lookup on them. 453 00:25:16,680 --> 00:25:23,455 And then I'll log this just to see what's going on. 454 00:25:23,455 --> 00:25:25,647 Clear this. 455 00:25:25,647 --> 00:25:32,140 And then I can see it's giving an array. 456 00:25:32,140 --> 00:25:33,700 And then it has a bunch of metadata. 457 00:25:33,700 --> 00:25:36,580 458 00:25:36,580 --> 00:25:41,220 And I'll just use the name from that. 459 00:25:41,220 --> 00:25:45,730 So I'll also take the zero index of this, 460 00:25:45,730 --> 00:25:48,880 just like I did with those other things that came in an array. 461 00:25:48,880 --> 00:25:52,240 And then here, where I don't have a description, 462 00:25:52,240 --> 00:25:56,260 I'll just say description equals this.state.where.name. 463 00:25:56,260 --> 00:26:00,250 464 00:26:00,250 --> 00:26:03,700 So now when I tap on the green pin here, it 465 00:26:03,700 --> 00:26:05,860 should say you are here, Radcliffe College. 466 00:26:05,860 --> 00:26:07,610 Or if you're in some other location, it'll 467 00:26:07,610 --> 00:26:10,460 probably say where you are based on the reverse geocode lookup. 468 00:26:10,460 --> 00:26:14,080 So now we have the beginnings of a map-based application based 469 00:26:14,080 --> 00:26:16,590 on using the maps and geolocation APIs. 470 00:26:16,590 --> 00:26:18,910 So that was pretty fun and cool. 471 00:26:18,910 --> 00:26:21,850 So now I'm gonna move on to the next thing. 472 00:26:21,850 --> 00:26:27,040 This is text or delete, which is something my sister sometimes 473 00:26:27,040 --> 00:26:28,720 does with me. 474 00:26:28,720 --> 00:26:29,590 She's a millennial. 475 00:26:29,590 --> 00:26:31,720 And so she plays this game where you have 476 00:26:31,720 --> 00:26:35,830 to go to the contacts app on your phone and spin through it until you find-- 477 00:26:35,830 --> 00:26:38,400 and then close your eyes, and then stop on a random contact. 478 00:26:38,400 --> 00:26:40,150 And then you have to decide whether you're 479 00:26:40,150 --> 00:26:42,250 going to text that person right then or you're just 480 00:26:42,250 --> 00:26:43,791 going to delete them from your phone. 481 00:26:43,791 --> 00:26:44,950 482 00:26:44,950 --> 00:26:47,710 And so I thought would be interesting to make an app that would 483 00:26:47,710 --> 00:26:49,750 go through your contacts and do this. 484 00:26:49,750 --> 00:26:52,317 485 00:26:52,317 --> 00:26:54,400 It's not actually that fun of a game in real life. 486 00:26:54,400 --> 00:26:55,850 It's mostly stressful. 487 00:26:55,850 --> 00:26:59,720 But we can make a way to do it. 488 00:26:59,720 --> 00:27:02,952 So I'm starting again with a fresh snack. 489 00:27:02,952 --> 00:27:05,410 I'll make the change again to just import Expo here instead 490 00:27:05,410 --> 00:27:07,030 of that constants thing. 491 00:27:07,030 --> 00:27:13,430 I'll delete this stuff, and then delete this stuff, as well. 492 00:27:13,430 --> 00:27:16,300 And then I have to change this to Expo.constants 493 00:27:16,300 --> 00:27:18,350 because I got rid of that. 494 00:27:18,350 --> 00:27:21,880 So the first thing I need to do is do something kind 495 00:27:21,880 --> 00:27:26,005 of similar where I'm just going to make a button that 496 00:27:26,005 --> 00:27:27,130 will pick a random contact. 497 00:27:27,130 --> 00:27:28,570 That'll be the first thing I do. 498 00:27:28,570 --> 00:27:35,730 So import-- oops, it looks like I deleted the import react 499 00:27:35,730 --> 00:27:36,730 native line by accident. 500 00:27:36,730 --> 00:27:40,120 501 00:27:40,120 --> 00:27:44,290 So I'm going to Import button so that I can use that. 502 00:27:44,290 --> 00:27:53,395 And now I'm just going to say a button title equals pick a random contact. 503 00:27:53,395 --> 00:27:57,320 504 00:27:57,320 --> 00:28:06,283 On press equals press. 505 00:28:06,283 --> 00:28:06,782 All 506 00:28:06,782 --> 00:28:09,550 Right So I'm just gonna make a button that when you press it, 507 00:28:09,550 --> 00:28:10,250 it says pressed. 508 00:28:10,250 --> 00:28:14,830 509 00:28:14,830 --> 00:28:20,390 So now I'm going to open this. 510 00:28:20,390 --> 00:28:24,001 511 00:28:24,001 --> 00:28:24,500 OK. 512 00:28:24,500 --> 00:28:26,350 So now we have this button here. 513 00:28:26,350 --> 00:28:28,780 When I tap this, it says pressed. 514 00:28:28,780 --> 00:28:29,280 OK. 515 00:28:29,280 --> 00:28:30,260 So we have a button that works. 516 00:28:30,260 --> 00:28:30,759 Cool. 517 00:28:30,759 --> 00:28:33,180 518 00:28:33,180 --> 00:28:35,850 So now when we hit the button, we want to open your contacts 519 00:28:35,850 --> 00:28:37,130 and get a random contact. 520 00:28:37,130 --> 00:28:44,790 So what I'm gonna do is get random contact async equals async. 521 00:28:44,790 --> 00:28:49,185 So now I've got to go back to the docs and look up contacts. 522 00:28:49,185 --> 00:28:51,930 523 00:28:51,930 --> 00:28:56,540 This needs permissions, actually, for your contacts. 524 00:28:56,540 --> 00:29:00,600 And so if you look at the example here, it awaits in basically the same way 525 00:29:00,600 --> 00:29:01,770 that we did before. 526 00:29:01,770 --> 00:29:05,840 So I'm just going to type that really quickly. 527 00:29:05,840 --> 00:29:14,520 Let status equals await expo.permissions.ask async expo 528 00:29:14,520 --> 00:29:17,760 permissions.contacts. 529 00:29:17,760 --> 00:29:23,740 If status doesn't equal granted console.error. 530 00:29:23,740 --> 00:29:27,806 531 00:29:27,806 --> 00:29:31,270 We'll just bail. 532 00:29:31,270 --> 00:29:33,700 Otherwise, we're going to then call-- 533 00:29:33,700 --> 00:29:37,030 now that we have permissions, we can call into the contacts API. 534 00:29:37,030 --> 00:29:41,630 If we look at this, there's a method called getContactsAsync. 535 00:29:41,630 --> 00:29:44,164 And it takes some options. 536 00:29:44,164 --> 00:29:47,080 The most naive implementation of this would just get all your contacts 537 00:29:47,080 --> 00:29:49,600 and return them in, like, a series of nested data 538 00:29:49,600 --> 00:29:52,210 structures like lists and objects. 539 00:29:52,210 --> 00:29:54,760 But some people have thousands of contacts on their phone. 540 00:29:54,760 --> 00:29:57,650 And so especially for older Android phones and things like that, 541 00:29:57,650 --> 00:30:00,067 it can take a really long time to read those off the place 542 00:30:00,067 --> 00:30:02,983 where they're stored, and then serialize them and put them into memory 543 00:30:02,983 --> 00:30:03,860 and copy them over. 544 00:30:03,860 --> 00:30:07,870 And so you don't really want to have these clunky applications where 545 00:30:07,870 --> 00:30:11,680 maybe they aren't even sure you need all the contacts, but the app gets really 546 00:30:11,680 --> 00:30:13,810 slowed down because it's loading all this stuff in. 547 00:30:13,810 --> 00:30:20,070 And so there's other ways to load in stuff, like, either paginated or by ID. 548 00:30:20,070 --> 00:30:22,160 So you can see in the object options here, 549 00:30:22,160 --> 00:30:24,810 there's this page size and page offset. 550 00:30:24,810 --> 00:30:29,560 And so let's just see what happens if we do a default request, 551 00:30:29,560 --> 00:30:31,610 like if we don't give any options. 552 00:30:31,610 --> 00:30:38,080 So let contacts equals await expo.contacts dot-- 553 00:30:38,080 --> 00:30:39,940 what is it? 554 00:30:39,940 --> 00:30:43,320 GetContactsAsync. 555 00:30:43,320 --> 00:30:45,780 And we just won't give any options. 556 00:30:45,780 --> 00:30:49,840 But we'll log what the answer is. 557 00:30:49,840 --> 00:30:56,630 And we'll stop saying pressed, and we'll just say this.getRandomContactAsync. 558 00:30:56,630 --> 00:31:02,157 So now when I push this button, I was hoping something would happen, 559 00:31:02,157 --> 00:31:02,740 but it didn't. 560 00:31:02,740 --> 00:31:09,380 561 00:31:09,380 --> 00:31:11,630 So now I'm just going to make sure I'm getting to here 562 00:31:11,630 --> 00:31:15,500 and not having permissions not granted. 563 00:31:15,500 --> 00:31:16,610 OK. 564 00:31:16,610 --> 00:31:19,910 So it's not getting my contacts. 565 00:31:19,910 --> 00:31:20,500 So why not? 566 00:31:20,500 --> 00:31:35,110 567 00:31:35,110 --> 00:31:36,090 Hmm. 568 00:31:36,090 --> 00:31:39,830 Maybe I need to actually fill out the options. 569 00:31:39,830 --> 00:31:45,700 So fields, page size, and page offset. 570 00:31:45,700 --> 00:31:58,883 So page size, let's just try one, and offset zero, and fields, we will say, 571 00:31:58,883 --> 00:31:59,845 phone numbers. 572 00:31:59,845 --> 00:32:08,022 573 00:32:08,022 --> 00:32:09,320 Ah, OK. 574 00:32:09,320 --> 00:32:11,190 So now we've got some data. 575 00:32:11,190 --> 00:32:15,920 So my first contact is Jack Freece on my phone. 576 00:32:15,920 --> 00:32:18,090 Has next page, has previous page. 577 00:32:18,090 --> 00:32:20,549 And it says I have 1,816 total contacts. 578 00:32:20,549 --> 00:32:23,840 So what I'm actually going to do is use the fact that it's giving me the total, 579 00:32:23,840 --> 00:32:25,730 and then use that to pick a random one. 580 00:32:25,730 --> 00:32:28,370 Because I'll just pick a random number between 1 and 816, 581 00:32:28,370 --> 00:32:30,394 or however many contacts I have on the phone. 582 00:32:30,394 --> 00:32:32,060 So what I'll do here is I'll await that. 583 00:32:32,060 --> 00:32:38,930 And then I'll say, let total equal contacts to pull that out from it. 584 00:32:38,930 --> 00:32:47,660 Then I'll say-- we'll let n equal a random number between 0 585 00:32:47,660 --> 00:32:49,580 and total minus 1. 586 00:32:49,580 --> 00:32:52,220 And then we'll log that number. 587 00:32:52,220 --> 00:32:55,910 So now I should see a log every time I push this button 588 00:32:55,910 --> 00:32:59,450 of a number between 0 and 815. 589 00:32:59,450 --> 00:33:02,310 So that seems like it's working. 590 00:33:02,310 --> 00:33:05,670 So now I just have to fetch that random person. 591 00:33:05,670 --> 00:33:16,040 So I'll say let random contact equal await getContactsAsync, page size 592 00:33:16,040 --> 00:33:21,110 one, offset n, fields phone numbers. 593 00:33:21,110 --> 00:33:23,780 594 00:33:23,780 --> 00:33:32,145 And now I'll log this random contact and see if I get a random contact. 595 00:33:32,145 --> 00:33:36,360 So when I clear this, I can see what's going on. 596 00:33:36,360 --> 00:33:39,730 So it looks like I got something. 597 00:33:39,730 --> 00:33:45,820 I got Jack Freece, which seems weird because that 598 00:33:45,820 --> 00:33:47,800 was the random thing I got last time. 599 00:33:47,800 --> 00:33:49,660 So I might be doing something wrong. 600 00:33:49,660 --> 00:33:52,220 601 00:33:52,220 --> 00:33:56,170 So hmm, maybe the offset isn't working. 602 00:33:56,170 --> 00:34:01,825 Or maybe I need to do page size n, offset zero. 603 00:34:01,825 --> 00:34:03,700 And then we'll get a whole bunch of contacts, 604 00:34:03,700 --> 00:34:05,450 and we'll be able to look at the last one. 605 00:34:05,450 --> 00:34:08,170 606 00:34:08,170 --> 00:34:10,230 So now I got 797. 607 00:34:10,230 --> 00:34:13,129 But I think it's loading almost all of my contacts into memory 608 00:34:13,129 --> 00:34:15,170 and trying to put them all into a data structure. 609 00:34:15,170 --> 00:34:17,402 So that might take too long. 610 00:34:17,402 --> 00:34:18,360 So that might not work. 611 00:34:18,360 --> 00:34:27,830 612 00:34:27,830 --> 00:34:30,820 And what if we don't ask for any phone numbers or anything? 613 00:34:30,820 --> 00:34:35,949 614 00:34:35,949 --> 00:34:36,449 OK. 615 00:34:36,449 --> 00:34:38,360 So now I've got 10 things. 616 00:34:38,360 --> 00:34:42,639 I think it's going to make me ask for each page of them. 617 00:34:42,639 --> 00:34:44,929 Now I'll just choose 100. 618 00:34:44,929 --> 00:34:47,870 So it looks like I'm going to have to get all the pages of stuff 619 00:34:47,870 --> 00:34:48,650 to make this work. 620 00:34:48,650 --> 00:34:52,670 621 00:34:52,670 --> 00:34:58,890 And so just in the interest of time, I'm not gonna write this loop. 622 00:34:58,890 --> 00:35:03,900 But I'm just gonna pick a random one between 1 and 100 and pick that out. 623 00:35:03,900 --> 00:35:07,720 And we'll just pretend I only have 100 contacts. 624 00:35:07,720 --> 00:35:18,720 And so from here, I think, under-- 625 00:35:18,720 --> 00:35:22,160 626 00:35:22,160 --> 00:35:24,695 let data equals random contacts. 627 00:35:24,695 --> 00:35:29,750 628 00:35:29,750 --> 00:35:30,530 Let's see. 629 00:35:30,530 --> 00:35:32,890 Equals data n. 630 00:35:32,890 --> 00:35:38,380 631 00:35:38,380 --> 00:35:43,190 So now I picked a random contact from the first 100 people on my phone. 632 00:35:43,190 --> 00:35:46,790 And it actually picked David Malan's sister, Lauren Malan. 633 00:35:46,790 --> 00:35:49,370 That's kind of funny. 634 00:35:49,370 --> 00:35:50,800 And so it's basically working. 635 00:35:50,800 --> 00:35:52,670 So now I just need to get phone numbers. 636 00:35:52,670 --> 00:35:55,670 So now I'm going to put phone numbers back in the fields here. 637 00:35:55,670 --> 00:35:57,950 And now I'll try again. 638 00:35:57,950 --> 00:36:02,700 And is it giving me his phone number? 639 00:36:02,700 --> 00:36:04,650 Maybe I don't have it. 640 00:36:04,650 --> 00:36:09,280 Well, I guess I'll just make do without having phone numbers. 641 00:36:09,280 --> 00:36:13,600 Or I'll check the documentation to make sure that was right. 642 00:36:13,600 --> 00:36:14,205 Phone numbers. 643 00:36:14,205 --> 00:36:17,740 644 00:36:17,740 --> 00:36:18,240 Ah. 645 00:36:18,240 --> 00:36:19,490 This is actually not a string. 646 00:36:19,490 --> 00:36:22,210 It's supposed to be expo.contacts.PHONE_NUMBERS. 647 00:36:22,210 --> 00:36:30,162 648 00:36:30,162 --> 00:36:31,487 OK. 649 00:36:31,487 --> 00:36:32,570 So now I'll do this again. 650 00:36:32,570 --> 00:36:36,590 651 00:36:36,590 --> 00:36:40,460 And someone named Steven. 652 00:36:40,460 --> 00:36:49,360 And I guess I don't have a phone number for him, actually. 653 00:36:49,360 --> 00:36:51,840 Oh, I did this wrong because I took this here. 654 00:36:51,840 --> 00:37:02,840 655 00:37:02,840 --> 00:37:03,390 OK. 656 00:37:03,390 --> 00:37:07,200 So now it has phone numbers. 657 00:37:07,200 --> 00:37:10,700 But I'm not going to show you people's phone numbers here. 658 00:37:10,700 --> 00:37:13,397 But now I'm getting the phone numbers. 659 00:37:13,397 --> 00:37:16,355 And so then I'm going to do a set state here now that I have a contact. 660 00:37:16,355 --> 00:37:22,390 661 00:37:22,390 --> 00:37:25,570 And then here, I'll just show their name if I have one. 662 00:37:25,570 --> 00:37:37,940 So I'll just say this.state.randomContact and text 663 00:37:37,940 --> 00:37:39,790 this.state.randomContact.name. 664 00:37:39,790 --> 00:37:48,010 665 00:37:48,010 --> 00:37:49,200 Or null. 666 00:37:49,200 --> 00:37:59,574 667 00:37:59,574 --> 00:38:01,070 Null is not an object. 668 00:38:01,070 --> 00:38:21,380 669 00:38:21,380 --> 00:38:22,374 Random contact. 670 00:38:22,374 --> 00:38:34,360 671 00:38:34,360 --> 00:38:37,940 So now I just have to set an initial value for random contact in state. 672 00:38:37,940 --> 00:38:41,910 So then when I do set state here, it's already populated, 673 00:38:41,910 --> 00:38:43,720 and now it can actually be checked here. 674 00:38:43,720 --> 00:38:47,485 So now when I pick a random contact, it shows me someone named Tom Cook. 675 00:38:47,485 --> 00:38:51,199 If I hit it again, now it says Jonas Looster, Elizabeth Windram. 676 00:38:51,199 --> 00:38:52,990 These are just random people from my phone. 677 00:38:52,990 --> 00:38:56,410 And so I think with future work, you could find a way 678 00:38:56,410 --> 00:38:58,840 to make that a link that would then send a text message 679 00:38:58,840 --> 00:39:02,180 or, like, put you in the texting app or take you to the contacts app, 680 00:39:02,180 --> 00:39:03,760 depending on what you choose. 681 00:39:03,760 --> 00:39:06,950 But I'm going to move on to other things. 682 00:39:06,950 --> 00:39:07,450 Cool. 683 00:39:07,450 --> 00:39:14,135 684 00:39:14,135 --> 00:39:14,635 Window. 685 00:39:14,635 --> 00:39:18,750 686 00:39:18,750 --> 00:39:22,880 So now I'm gonna show you making a quick compass. 687 00:39:22,880 --> 00:39:24,180 I'm gonna make a new Snack. 688 00:39:24,180 --> 00:39:28,080 689 00:39:28,080 --> 00:39:34,250 And I'm again just gonna delete this junk and just say Expo here. 690 00:39:34,250 --> 00:39:38,360 691 00:39:38,360 --> 00:39:44,860 Say Expo.constants there, and then get rid of this stuff, 692 00:39:44,860 --> 00:39:47,905 and then run on device, Android. 693 00:39:47,905 --> 00:39:51,030 694 00:39:51,030 --> 00:39:51,750 Open this up. 695 00:39:51,750 --> 00:39:54,270 696 00:39:54,270 --> 00:39:57,780 So now one of the cool things that a phone has that computers don't normally 697 00:39:57,780 --> 00:40:00,600 have or whatever is a compass in them. 698 00:40:00,600 --> 00:40:02,790 It's called a magnetometer formally. 699 00:40:02,790 --> 00:40:09,580 And so we're going to look at the API here for it. 700 00:40:09,580 --> 00:40:12,070 And it's really, really simple to use. 701 00:40:12,070 --> 00:40:14,880 You can say, basically, Expo Magnetometer at listener. 702 00:40:14,880 --> 00:40:17,224 And we'll just do that. 703 00:40:17,224 --> 00:40:19,140 But what I'm going to do is I'm actually going 704 00:40:19,140 --> 00:40:26,230 to upload some files really quickly that should make our life easier. 705 00:40:26,230 --> 00:40:31,110 So I'm going to upload this compass face. 706 00:40:31,110 --> 00:40:35,290 And I'm going to include this compass needle. 707 00:40:35,290 --> 00:40:43,180 708 00:40:43,180 --> 00:40:47,770 So now I'm just going to say image and image 709 00:40:47,770 --> 00:40:49,720 background we're going to import here. 710 00:40:49,720 --> 00:40:52,240 And I'm just going to draw a simple compass on the screen 711 00:40:52,240 --> 00:40:55,320 here that we can actually turn into a real compass. 712 00:40:55,320 --> 00:41:02,820 So I'm going to say image background source equals require compass face 713 00:41:02,820 --> 00:41:06,820 that I just uploaded to this project. 714 00:41:06,820 --> 00:41:13,970 And that is, I think, height 320, width 320. 715 00:41:13,970 --> 00:41:16,840 And then I'm going to have a compass needle here inside of it. 716 00:41:16,840 --> 00:41:42,220 717 00:41:42,220 --> 00:41:42,720 OK. 718 00:41:42,720 --> 00:41:44,454 So now this looks almost right. 719 00:41:44,454 --> 00:41:46,620 But the needle isn't really centered on the compass. 720 00:41:46,620 --> 00:41:51,120 So I'm going to say align items, center, justify contents, center. 721 00:41:51,120 --> 00:41:53,620 Then I'm going to make this needle a little bit transparent. 722 00:41:53,620 --> 00:41:56,940 I'm going to say opacity 0.65. 723 00:41:56,940 --> 00:41:57,611 Bam. 724 00:41:57,611 --> 00:41:59,610 Now we have a compass that's looking pretty good 725 00:41:59,610 --> 00:42:02,234 except that I can move my phone around in different directions, 726 00:42:02,234 --> 00:42:03,340 and nothing happens. 727 00:42:03,340 --> 00:42:05,340 So now I'm going to use the magnetometer to make 728 00:42:05,340 --> 00:42:06,842 it actually function like a compass. 729 00:42:06,842 --> 00:42:07,800 So this is pretty easy. 730 00:42:07,800 --> 00:42:11,940 So I'm gonna state is ready. 731 00:42:11,940 --> 00:42:13,230 False. 732 00:42:13,230 --> 00:42:17,530 And it just won't be ready until then. 733 00:42:17,530 --> 00:42:24,269 And then I'm going to say component did mount, this.setupMagnetometerAsync. 734 00:42:24,269 --> 00:42:32,740 735 00:42:32,740 --> 00:42:37,940 setupMagnetometerAsync equals an async function. 736 00:42:37,940 --> 00:42:40,700 And then looking at the magnetometer docs, all you need to do 737 00:42:40,700 --> 00:42:42,560 is add a listener here. 738 00:42:42,560 --> 00:42:44,820 So I'm gonna add a listener. 739 00:42:44,820 --> 00:42:47,441 And this just takes a function. 740 00:42:47,441 --> 00:42:50,310 Oops. 741 00:42:50,310 --> 00:42:59,390 And we'll just say this is like a vector. 742 00:42:59,390 --> 00:43:08,510 So we'll just have that say this set state V for that vector. 743 00:43:08,510 --> 00:43:13,650 744 00:43:13,650 --> 00:43:15,030 OK, cool. 745 00:43:15,030 --> 00:43:19,620 And so now there's a little bit of math you 746 00:43:19,620 --> 00:43:22,330 need to do to turn that into something. 747 00:43:22,330 --> 00:43:24,720 So we'll just see what the vector thing is. 748 00:43:24,720 --> 00:43:27,792 Text this.state.V. Text. 749 00:43:27,792 --> 00:43:33,684 750 00:43:33,684 --> 00:43:48,910 [INAUDIBLE] 751 00:43:48,910 --> 00:43:51,860 So now I'm showing what v is on the screen here. 752 00:43:51,860 --> 00:43:56,000 And you can see it's got, like, X, Y, and Z components here to it. 753 00:43:56,000 --> 00:43:59,440 And so we somehow need to turn that into a directional heading. 754 00:43:59,440 --> 00:44:02,460 And you can actually Google around and find how to do that. 755 00:44:02,460 --> 00:44:05,200 Making a compass-- 756 00:44:05,200 --> 00:44:07,750 I think I can remember it off the top of my head, though. 757 00:44:07,750 --> 00:44:19,150 I think it's something like let data equals 0 radians. 758 00:44:19,150 --> 00:44:31,485 If this.state.V theta equals math.atan negative V X. 759 00:44:31,485 --> 00:44:36,490 Well, let's say, let x, y, z-- 760 00:44:36,490 --> 00:44:38,800 we'll pull x, y, and z out of the vector. 761 00:44:38,800 --> 00:44:41,810 And then we'll do this. 762 00:44:41,810 --> 00:44:54,926 If negative is greater than zero and y is greater than zero, then nothing. 763 00:44:54,926 --> 00:45:00,300 Else if y is greater than zero, theta plus equals math.pi. 764 00:45:00,300 --> 00:45:03,795 765 00:45:03,795 --> 00:45:11,820 Else theta plus equals math.pi times 2. 766 00:45:11,820 --> 00:45:14,530 767 00:45:14,530 --> 00:45:25,270 And then so now instead of showing the vector, 768 00:45:25,270 --> 00:45:32,870 I'm going to try showing the angle in radians. 769 00:45:32,870 --> 00:45:36,470 And you can see as I move it, that changes. 770 00:45:36,470 --> 00:45:39,410 771 00:45:39,410 --> 00:45:44,150 So what I'm going to do is now I'm going to try to rotate the needle so 772 00:45:44,150 --> 00:45:46,155 that it like turns that many degrees. 773 00:45:46,155 --> 00:45:51,740 What we can do for that is we can just use this transform thing, which 774 00:45:51,740 --> 00:45:56,297 takes a property like rotate, I think, or rotation. 775 00:45:56,297 --> 00:45:57,130 Let me look that up. 776 00:45:57,130 --> 00:46:10,281 777 00:46:10,281 --> 00:46:13,280 Under Transforms in the React Native docs, you can see it does rotation. 778 00:46:13,280 --> 00:46:16,890 779 00:46:16,890 --> 00:46:22,300 And so I'm just gonna say rotation theta. 780 00:46:22,300 --> 00:46:30,510 781 00:46:30,510 --> 00:46:32,410 Maybe it's rotate. 782 00:46:32,410 --> 00:46:33,410 Oh, yeah. 783 00:46:33,410 --> 00:46:35,970 OK. 784 00:46:35,970 --> 00:46:39,570 So now you can see-- it's maybe hard to tell on the screen at the same time, 785 00:46:39,570 --> 00:46:43,260 but now as I move-- 786 00:46:43,260 --> 00:46:46,770 I think I made a mistake somewhere because the thing flips around 787 00:46:46,770 --> 00:46:48,270 sometimes. 788 00:46:48,270 --> 00:46:52,970 But in general, you basically have a working compass now. 789 00:46:52,970 --> 00:46:56,320 So that's pretty cool. 790 00:46:56,320 --> 00:47:01,654 Another thing is there's actually a whole bunch of sensors on the phone. 791 00:47:01,654 --> 00:47:03,570 There's not just the magnetometer, but there's 792 00:47:03,570 --> 00:47:08,105 an accelerometer, a gyroscope, a pedometer, GPS, and a camera 793 00:47:08,105 --> 00:47:08,980 and things like that. 794 00:47:08,980 --> 00:47:11,370 And so you can actually combine all these things 795 00:47:11,370 --> 00:47:14,970 and get more information because some of them collect overlapping information. 796 00:47:14,970 --> 00:47:17,844 Or you can combine it together, and you can be pretty smart about it. 797 00:47:17,844 --> 00:47:22,380 And so that whole study of that is called sensor fusion. 798 00:47:22,380 --> 00:47:24,150 And there's sort of a standardized output 799 00:47:24,150 --> 00:47:30,360 from that that's called device motion that has been exposed in iOS APIs 800 00:47:30,360 --> 00:47:32,220 and also in Android APIs. 801 00:47:32,220 --> 00:47:36,030 And so if you use device motion, you can actually get information 802 00:47:36,030 --> 00:47:41,400 about the orientation of a phone that's from the combination of all 803 00:47:41,400 --> 00:47:42,810 these different sensors. 804 00:47:42,810 --> 00:47:45,300 And that's actually exposed in Expo, as well. 805 00:47:45,300 --> 00:47:50,520 So we can do kind of a cool demo if we do something where 806 00:47:50,520 --> 00:47:54,840 we could even just take this and-- 807 00:47:54,840 --> 00:48:02,930 well, I'll just take out this stuff. 808 00:48:02,930 --> 00:48:08,760 And instead of this, I'll just put in an image. 809 00:48:08,760 --> 00:48:14,260 810 00:48:14,260 --> 00:48:21,142 I'm gonna upload-- show the files here. 811 00:48:21,142 --> 00:48:24,515 And I'll upload these balloons. 812 00:48:24,515 --> 00:48:28,660 813 00:48:28,660 --> 00:48:31,520 Get rid of the files. 814 00:48:31,520 --> 00:48:33,020 So I just uploaded some balloons. 815 00:48:33,020 --> 00:48:34,375 And I'm gonna just show them. 816 00:48:34,375 --> 00:48:41,550 And I'm gonna say source equals require uphouse.jpeg. 817 00:48:41,550 --> 00:48:44,380 818 00:48:44,380 --> 00:48:48,510 Style equals-- how big is that thing? 819 00:48:48,510 --> 00:48:55,320 820 00:48:55,320 --> 00:49:04,900 1440 by 1280. 821 00:49:04,900 --> 00:49:10,680 And then let's multiply it by, like, 0.7 just so that it's 822 00:49:10,680 --> 00:49:12,391 vaguely fitting on the screen. 823 00:49:12,391 --> 00:49:12,890 Cool. 824 00:49:12,890 --> 00:49:16,110 825 00:49:16,110 --> 00:49:17,290 So now we have this house. 826 00:49:17,290 --> 00:49:23,220 But now instead of using compass stuff, let's use device motion instead. 827 00:49:23,220 --> 00:49:26,950 So instead of setting up the magnetometer, 828 00:49:26,950 --> 00:49:28,490 let's set up device motion. 829 00:49:28,490 --> 00:49:35,010 830 00:49:35,010 --> 00:49:36,030 And then we do that. 831 00:49:36,030 --> 00:49:37,575 We can take a look at this and say-- 832 00:49:37,575 --> 00:49:40,392 833 00:49:40,392 --> 00:49:42,600 we just add a listener, and we'll get something else. 834 00:49:42,600 --> 00:49:47,240 835 00:49:47,240 --> 00:49:50,130 But it's pretty similar. 836 00:49:50,130 --> 00:49:56,108 Device motion add listener. 837 00:49:56,108 --> 00:50:01,610 Device motion-- we'll just call what the output of device motion listener 838 00:50:01,610 --> 00:50:05,940 DM for device motion. 839 00:50:05,940 --> 00:50:07,700 So we'll set that state. 840 00:50:07,700 --> 00:50:12,650 And then instead of doing all this junk to get data, 841 00:50:12,650 --> 00:50:30,770 we'll just say let angle equals zero if this.state.dm 842 00:50:30,770 --> 00:50:32,960 and this.state.dm.rotation.gamma. 843 00:50:32,960 --> 00:50:37,910 844 00:50:37,910 --> 00:50:41,900 We'll say angle equals this.state.dm.rotation.gamme. 845 00:50:41,900 --> 00:50:45,540 846 00:50:45,540 --> 00:50:46,300 OK. 847 00:50:46,300 --> 00:50:51,585 And then we'll do a rotation transform on this, just like we did before. 848 00:50:51,585 --> 00:51:02,420 849 00:51:02,420 --> 00:51:04,270 And let's see. 850 00:51:04,270 --> 00:51:08,374 851 00:51:08,374 --> 00:51:15,530 Ah, we need to set up the device motion. 852 00:51:15,530 --> 00:51:20,670 Now, if we do this then-- 853 00:51:20,670 --> 00:51:25,100 let me log what we're getting here. 854 00:51:25,100 --> 00:51:32,692 855 00:51:32,692 --> 00:51:33,192 Huh. 856 00:51:33,192 --> 00:51:34,150 All right. 857 00:51:34,150 --> 00:51:38,090 We're not getting anything listened from the device motion. 858 00:51:38,090 --> 00:51:40,960 Why is that not the case? 859 00:51:40,960 --> 00:51:44,090 Oh, device motion is actually under danger zone, 860 00:51:44,090 --> 00:51:47,930 which is called danger zone because the API might change, 861 00:51:47,930 --> 00:51:49,070 and it's sort of in beta. 862 00:51:49,070 --> 00:51:52,042 It's safe to use, but if you want to keep using it, 863 00:51:52,042 --> 00:51:54,500 you might have to learn new stuff when new things come out. 864 00:51:54,500 --> 00:51:56,660 I forgot that, and I forgot to put in the danger zone thing, 865 00:51:56,660 --> 00:51:58,460 and that's why it's not working right now. 866 00:51:58,460 --> 00:52:02,180 But all I need to do to fix that is say danger zone here. 867 00:52:02,180 --> 00:52:04,450 And then I probably don't need this log. 868 00:52:04,450 --> 00:52:07,185 But now you can see as I rotate this, the balloons 869 00:52:07,185 --> 00:52:08,810 are kind of spinning around like crazy. 870 00:52:08,810 --> 00:52:12,260 What I'm trying to do is actually make them always point up. 871 00:52:12,260 --> 00:52:14,260 So you can see what I'm doing is when I tilt it, 872 00:52:14,260 --> 00:52:16,320 it actually rotates even further. 873 00:52:16,320 --> 00:52:20,030 So what I want to do instead is compensate and actually 874 00:52:20,030 --> 00:52:21,410 have it be the opposite of that. 875 00:52:21,410 --> 00:52:25,010 So I'm going to rotate it by the negative of the rotation of the device. 876 00:52:25,010 --> 00:52:27,960 877 00:52:27,960 --> 00:52:32,000 So if I do that, then now if you-- see this? 878 00:52:32,000 --> 00:52:34,040 No matter how I rotate my phone, the balloons 879 00:52:34,040 --> 00:52:38,270 are always kind of going up in the air. 880 00:52:38,270 --> 00:52:39,430 It's a little choppy. 881 00:52:39,430 --> 00:52:42,320 And so what we can actually do is we can tell the device motion 882 00:52:42,320 --> 00:52:46,040 sensor to detect every frame. 883 00:52:46,040 --> 00:52:51,590 So we can say Expo.dangerZone.Devicemotion 884 00:52:51,590 --> 00:52:54,515 set update interval to 16. 885 00:52:54,515 --> 00:52:57,680 886 00:52:57,680 --> 00:53:00,950 That's the other method you can see here, set update interval. 887 00:53:00,950 --> 00:53:05,240 The reason we do 16 is that iPhones and Android phones 888 00:53:05,240 --> 00:53:09,140 tend to render stuff at, like, 60 frames per second, which is 889 00:53:09,140 --> 00:53:12,230 pretty good for viewing the human eye. 890 00:53:12,230 --> 00:53:14,150 There's one model of new iPad that renders 891 00:53:14,150 --> 00:53:15,770 at, like, 120 frames per second. 892 00:53:15,770 --> 00:53:19,100 But almost all sort of modern phones do 60 frames per second now when they can. 893 00:53:19,100 --> 00:53:21,590 When they drop frames, it's like a miss, and that's 894 00:53:21,590 --> 00:53:24,440 when you see jerkiness in the UI and stuff. 895 00:53:24,440 --> 00:53:32,120 So if you divide 1,000 milliseconds by 60 frames, 896 00:53:32,120 --> 00:53:34,190 you end up with 16 milliseconds. 897 00:53:34,190 --> 00:53:36,350 And so that's why we use 16 here, because that 898 00:53:36,350 --> 00:53:40,730 means we'll get an update from the device motion API every frame. 899 00:53:40,730 --> 00:53:43,610 So when we do this, now, if you can tell, 900 00:53:43,610 --> 00:53:47,270 this is really smooth because it's updating every single frame. 901 00:53:47,270 --> 00:53:50,840 And even though it looks not like it on the screen, on my phone 902 00:53:50,840 --> 00:53:52,550 the balloons are always pointing up. 903 00:53:52,550 --> 00:53:53,750 Cool. 904 00:53:53,750 --> 00:53:55,640 So we'll take a little break for a while, 905 00:53:55,640 --> 00:53:58,400 and then I'll come back and do some more stuff. 906 00:53:58,400 --> 00:53:59,730 Thanks. 907 00:53:59,730 --> 00:54:00,230 Hey. 908 00:54:00,230 --> 00:54:02,000 Welcome back. 909 00:54:02,000 --> 00:54:03,170 There was one sidenote. 910 00:54:03,170 --> 00:54:04,830 Somebody asked about this. 911 00:54:04,830 --> 00:54:10,580 Yeah, I kind of glossed over it, but when you add those listeners 912 00:54:10,580 --> 00:54:16,190 for device motion or for magnetometer, you should actually remove them 913 00:54:16,190 --> 00:54:17,510 when your component unmounts. 914 00:54:17,510 --> 00:54:19,926 Otherwise, you can accumulate lots of these listeners that 915 00:54:19,926 --> 00:54:23,540 aren't doing anything that are wasting resources or keeping the device running 916 00:54:23,540 --> 00:54:24,870 and wasting battery. 917 00:54:24,870 --> 00:54:28,447 So just calling this remove all listeners or storing 918 00:54:28,447 --> 00:54:31,030 the value of [? AdListener, ?] and then calling remove on that 919 00:54:31,030 --> 00:54:32,150 is how you do that. 920 00:54:32,150 --> 00:54:34,490 But in a basic demo application or something like that, 921 00:54:34,490 --> 00:54:35,739 it's not the end of the world. 922 00:54:35,739 --> 00:54:38,364 It's sort of like just not cleaning up after yourself. 923 00:54:38,364 --> 00:54:41,030 So the next thing we're going to do is do some multimedia stuff. 924 00:54:41,030 --> 00:54:43,030 This is something that people always like doing, 925 00:54:43,030 --> 00:54:47,520 is stuff with video, images, audio, stuff like that. 926 00:54:47,520 --> 00:54:51,592 So I'm gonna make a basic what I call multimedia board. 927 00:54:51,592 --> 00:54:54,830 Basically, the idea is one of the soundboards like people made-- 928 00:54:54,830 --> 00:55:00,440 Arnold Schwarzenegger soundboards or "The Office" soundboards or Snoop Dogg 929 00:55:00,440 --> 00:55:01,450 soundboards. 930 00:55:01,450 --> 00:55:05,240 I'm gonna do the same thing, but with videos instead. 931 00:55:05,240 --> 00:55:06,520 So what I've got-- 932 00:55:06,520 --> 00:55:11,810 I'll just start by showing a quick CAD video. 933 00:55:11,810 --> 00:55:14,260 What I'm gonna use here is just a text editor. 934 00:55:14,260 --> 00:55:16,932 I'm using VS Code. 935 00:55:16,932 --> 00:55:18,140 But you can use whatever one. 936 00:55:18,140 --> 00:55:21,500 And I'm gonna use the Expo XDE instead of Snack 937 00:55:21,500 --> 00:55:25,480 because the way Snack does reloading, when you use videos, especially, 938 00:55:25,480 --> 00:55:28,610 and audio stuff, having all the multimedia objects 939 00:55:28,610 --> 00:55:32,120 plus that kind of reloading tends to just overload the phone. 940 00:55:32,120 --> 00:55:33,824 And it just kind of breaks. 941 00:55:33,824 --> 00:55:35,740 So it's gonna work better to do this this way. 942 00:55:35,740 --> 00:55:37,490 So I've got it opened up here. 943 00:55:37,490 --> 00:55:40,110 944 00:55:40,110 --> 00:55:42,860 Here's the app, and then here's my editor. 945 00:55:42,860 --> 00:55:49,910 I'm gonna close these and move this over. 946 00:55:49,910 --> 00:55:57,490 Minimize this and this so we can see the phone as we type. 947 00:55:57,490 --> 00:55:58,174 OK. 948 00:55:58,174 --> 00:55:59,340 And now I'm just gonna say-- 949 00:55:59,340 --> 00:56:03,090 950 00:56:03,090 --> 00:56:08,720 just as a test, I'm gonna delete this and just say cat sounds. 951 00:56:08,720 --> 00:56:10,911 Save it, and then this should reload. 952 00:56:10,911 --> 00:56:13,035 Takes a little longer because we're not using Snack 953 00:56:13,035 --> 00:56:14,630 because it's downloading this whole bundle. 954 00:56:14,630 --> 00:56:14,840 All right. 955 00:56:14,840 --> 00:56:15,430 But it worked. 956 00:56:15,430 --> 00:56:15,930 Cool. 957 00:56:15,930 --> 00:56:21,770 So now the first thing we're going to do is we're going to stick in a cat video. 958 00:56:21,770 --> 00:56:26,060 So we're going to say video Expo.video. 959 00:56:26,060 --> 00:56:28,860 960 00:56:28,860 --> 00:56:32,390 Let's look up the docs for this just so we have somewhere to start. 961 00:56:32,390 --> 00:56:37,260 962 00:56:37,260 --> 00:56:40,060 And you can see there's a bunch of options that it takes. 963 00:56:40,060 --> 00:56:43,520 But they're pretty basic. 964 00:56:43,520 --> 00:56:52,220 And so we can just start by just saying source require dot slash-- 965 00:56:52,220 --> 00:56:56,730 I think-- let me look at this directory. 966 00:56:56,730 --> 00:56:58,880 So I have an assets folder. 967 00:56:58,880 --> 00:57:05,300 And inside it, I have a font and nine little short videos of cats, 968 00:57:05,300 --> 00:57:06,690 plus some weird sound effects. 969 00:57:06,690 --> 00:57:09,540 So here's one of them. 970 00:57:09,540 --> 00:57:11,210 So I'm gonna try to play that one. 971 00:57:11,210 --> 00:57:14,060 So I'm gonna say require assets1.mp4. 972 00:57:14,060 --> 00:57:16,970 973 00:57:16,970 --> 00:57:19,080 And then I'm going to give this a style. 974 00:57:19,080 --> 00:57:28,066 So I'm going to say, just so we can see it, width 400, height 400. 975 00:57:28,066 --> 00:57:28,985 OK. 976 00:57:28,985 --> 00:57:32,240 And we'll just close that like that. 977 00:57:32,240 --> 00:57:38,680 And now if I save this, I think we should-- oops, made a mistake. 978 00:57:38,680 --> 00:57:39,770 Oops, I forgot this. 979 00:57:39,770 --> 00:57:42,722 980 00:57:42,722 --> 00:57:43,706 Closing bracket. 981 00:57:43,706 --> 00:57:53,521 982 00:57:53,521 --> 00:57:54,020 Cool. 983 00:57:54,020 --> 00:57:59,070 So now I have a cat video here, but it's not playing, and it's just right there. 984 00:57:59,070 --> 00:58:05,900 So now I'm going to switch this to say shouldPlay equals true. 985 00:58:05,900 --> 00:58:07,600 I think that's right, looking at this. 986 00:58:07,600 --> 00:58:09,020 Yeah, OK. 987 00:58:09,020 --> 00:58:10,190 Save this. 988 00:58:10,190 --> 00:58:14,720 So now-- now the video plays. 989 00:58:14,720 --> 00:58:16,497 OK, cool. 990 00:58:16,497 --> 00:58:18,830 There's a couple of things that aren't great about this. 991 00:58:18,830 --> 00:58:21,800 One is I can't hear any sound. 992 00:58:21,800 --> 00:58:25,460 So part of this is that my phone's on silent right now, actually. 993 00:58:25,460 --> 00:58:29,066 So one thing I can do is I can turn my phone off silent, which I just did. 994 00:58:29,066 --> 00:58:32,652 And I'm going to save this again so that it loads up again. 995 00:58:32,652 --> 00:58:34,360 And now I think we should hear the sound. 996 00:58:34,360 --> 00:58:38,008 997 00:58:38,008 --> 00:58:38,881 [MUSIC PLAYING] 998 00:58:38,881 --> 00:58:39,300 999 00:58:39,300 --> 00:58:39,800 Yep. 1000 00:58:39,800 --> 00:58:40,030 OK. 1001 00:58:40,030 --> 00:58:42,570 So the sound played, but I don't want to have to always turn on my phone 1002 00:58:42,570 --> 00:58:44,430 to not silent just to hear this stuff. 1003 00:58:44,430 --> 00:58:48,091 Because if I'm going into this app, half the point is to hear the sounds. 1004 00:58:48,091 --> 00:58:50,340 So we can actually switch the audio mode so that it'll 1005 00:58:50,340 --> 00:58:53,010 play while the phone is on silent. 1006 00:58:53,010 --> 00:59:02,760 And the way we do that is if we look at the docs under audio, set-- 1007 00:59:02,760 --> 00:59:08,490 1008 00:59:08,490 --> 00:59:09,600 we can actually set it up. 1009 00:59:09,600 --> 00:59:14,850 So I'll just write a method here that's like-- 1010 00:59:14,850 --> 00:59:26,300 1011 00:59:26,300 --> 00:59:29,060 And I'll say Expo audio-- 1012 00:59:29,060 --> 00:59:33,758 1013 00:59:33,758 --> 00:59:36,650 oops. 1014 00:59:36,650 --> 00:59:38,950 Import Expo from Expo. 1015 00:59:38,950 --> 00:59:39,450 OK. 1016 00:59:39,450 --> 00:59:44,460 1017 00:59:44,460 --> 00:59:47,400 Set audio mode async. 1018 00:59:47,400 --> 00:59:50,520 And then this is going to take some parameters. 1019 00:59:50,520 --> 00:59:55,885 So one thing it's going to take is play in silent mode on iOS. 1020 00:59:55,885 --> 00:59:57,343 So we're going to set this to True. 1021 00:59:57,343 --> 01:00:00,584 1022 01:00:00,584 --> 01:00:02,600 And we'll await this. 1023 01:00:02,600 --> 01:00:07,810 1024 01:00:07,810 --> 01:00:17,140 So now we're going to say component will mount this.setAudioModeAsync. 1025 01:00:17,140 --> 01:00:17,660 OK. 1026 01:00:17,660 --> 01:00:21,470 So now I think if I save this, this should play, 1027 01:00:21,470 --> 01:00:25,921 even though my phone is back in silent mode. 1028 01:00:25,921 --> 01:00:27,853 Huh. 1029 01:00:27,853 --> 01:00:32,590 Audio mode attempted without the required keys. 1030 01:00:32,590 --> 01:00:34,670 Oh, so I need to fill in more keys. 1031 01:00:34,670 --> 01:00:39,850 So allows recording iOS, false, because we're not going to record anything. 1032 01:00:39,850 --> 01:00:42,820 1033 01:00:42,820 --> 01:00:45,940 If you want to watch the basketball championship game, it's on right now. 1034 01:00:45,940 --> 01:00:48,410 And you can come watch this on video later. 1035 01:00:48,410 --> 01:00:50,545 [INAUDIBLE] Android true. 1036 01:00:50,545 --> 01:00:54,910 1037 01:00:54,910 --> 01:00:59,050 Interruption mode Android Expo audio. 1038 01:00:59,050 --> 01:01:03,860 Interruption mode, Android, duck others. 1039 01:01:03,860 --> 01:01:08,020 Interruption mode, iOS, Expo audio. 1040 01:01:08,020 --> 01:01:12,220 Interruption iOS, mix with others. 1041 01:01:12,220 --> 01:01:15,580 Don't worry too much about what all these things are because you 1042 01:01:15,580 --> 01:01:17,110 can just kind of copy these. 1043 01:01:17,110 --> 01:01:21,190 And then when you want to start doing very particular things with audio, 1044 01:01:21,190 --> 01:01:22,720 you can kind of learn what they are. 1045 01:01:22,720 --> 01:01:24,700 They're basically about if there's another sound playing 1046 01:01:24,700 --> 01:01:27,430 in the background-- like if you had Spotify playing music-- 1047 01:01:27,430 --> 01:01:29,950 then how should your app interact with that? 1048 01:01:29,950 --> 01:01:32,839 Should it stop the music temporarily, and then do stuff? 1049 01:01:32,839 --> 01:01:34,130 Or should it just play over it? 1050 01:01:34,130 --> 01:01:35,609 Et cetera, et cetera. 1051 01:01:35,609 --> 01:01:38,150 And you can look through the docs to find out what these are. 1052 01:01:38,150 --> 01:01:45,250 But hopefully, this is enough that by saving this, this will now work. 1053 01:01:45,250 --> 01:01:45,750 OK. 1054 01:01:45,750 --> 01:01:54,444 1055 01:01:54,444 --> 01:01:55,410 [MUSIC PLAYING] 1056 01:01:55,410 --> 01:01:55,970 There we go. 1057 01:01:55,970 --> 01:01:57,090 So now the sound played. 1058 01:01:57,090 --> 01:01:59,530 Cool. 1059 01:01:59,530 --> 01:02:01,950 So now the other thing is I kind of want all these videos 1060 01:02:01,950 --> 01:02:04,350 to be sort of square buttons. 1061 01:02:04,350 --> 01:02:07,440 And so I said height 400, width 400. 1062 01:02:07,440 --> 01:02:11,580 But you can see that it's kind of a rectangly type thing. 1063 01:02:11,580 --> 01:02:21,510 So what I can do here is I can say resize mode equals-- 1064 01:02:21,510 --> 01:02:22,960 and I can say cover. 1065 01:02:22,960 --> 01:02:26,880 And that will cause this to make the video fill 1066 01:02:26,880 --> 01:02:28,720 the space that I give it in the style. 1067 01:02:28,720 --> 01:02:30,675 And so now I should see a square video now. 1068 01:02:30,675 --> 01:02:31,780 And I do. 1069 01:02:31,780 --> 01:02:32,280 Cool. 1070 01:02:32,280 --> 01:02:34,850 1071 01:02:34,850 --> 01:02:39,130 And so now I want to make it so that when this video gets to the end, 1072 01:02:39,130 --> 01:02:43,770 it's not a black square, which is boring and doesn't look right, 1073 01:02:43,770 --> 01:02:47,560 but it actually goes back to the first frame of the video. 1074 01:02:47,560 --> 01:02:51,537 And so the way I do that is I actually have to listen for when the-- 1075 01:02:51,537 --> 01:02:53,370 it's actually fairly complicated to do this. 1076 01:02:53,370 --> 01:02:56,550 But I have to basically listen for when the video ends, get a callback, 1077 01:02:56,550 --> 01:02:59,220 and then reset the frame position of it. 1078 01:02:59,220 --> 01:03:04,560 And so to even start doing that, I need to use refs and stuff. 1079 01:03:04,560 --> 01:03:08,810 So I'm actually going to break this out into its own component. 1080 01:03:08,810 --> 01:03:17,930 So I'm going to make a new one called cat video button extends 1081 01:03:17,930 --> 01:03:19,680 React component. 1082 01:03:19,680 --> 01:03:24,140 And this has a render method, which is just going to be this. 1083 01:03:24,140 --> 01:03:34,140 1084 01:03:34,140 --> 01:03:46,520 And I'm gonna say this.props.width or this.props.size or 400, 1085 01:03:46,520 --> 01:03:52,171 this.props.height or this.props.size or 400. 1086 01:03:52,171 --> 01:03:52,670 OK. 1087 01:03:52,670 --> 01:03:57,300 And I'm gonna say this.props.source for this 1088 01:03:57,300 --> 01:04:02,190 so that I can parameterize this and use it for all the different cat 1089 01:04:02,190 --> 01:04:05,260 video buttons. 1090 01:04:05,260 --> 01:04:18,860 So I'm just gonna throw cat video button source equals require assets 1.mp4. 1091 01:04:18,860 --> 01:04:24,986 And we'll say it's just 100 now. 1092 01:04:24,986 --> 01:04:32,610 1093 01:04:32,610 --> 01:04:36,150 So if this works, I should see a smaller cat button. 1094 01:04:36,150 --> 01:04:37,510 There we go. 1095 01:04:37,510 --> 01:04:38,010 Perfect. 1096 01:04:38,010 --> 01:04:41,520 1097 01:04:41,520 --> 01:04:45,690 So now I'm gonna try to make this so that it goes back to the first thing. 1098 01:04:45,690 --> 01:04:49,080 So I'm gonna have to make a ref here, which is-- 1099 01:04:49,080 --> 01:04:51,175 I think you probably covered this. 1100 01:04:51,175 --> 01:04:56,590 But basically, this takes a function that's passed to the component itself. 1101 01:04:56,590 --> 01:04:59,550 And then you can do something so that you can, like, 1102 01:04:59,550 --> 01:05:05,350 in this component set a variable that's a reference to this component. 1103 01:05:05,350 --> 01:05:07,104 So inside the cat video button, I'm going 1104 01:05:07,104 --> 01:05:09,270 to have an instance variable that points to the Expo 1105 01:05:09,270 --> 01:05:11,730 video that is the actual cat video. 1106 01:05:11,730 --> 01:05:14,010 And so this.video equals c. 1107 01:05:14,010 --> 01:05:16,570 C is for component here. 1108 01:05:16,570 --> 01:05:18,870 OK. 1109 01:05:18,870 --> 01:05:24,750 So then there's this callback called onPlaybackStatusUpdate. 1110 01:05:24,750 --> 01:05:34,660 And that's going to get playbackStatusUpdate. 1111 01:05:34,660 --> 01:05:41,619 And if it has this did just finish property, it mean it just finished. 1112 01:05:41,619 --> 01:05:42,910 So I'm only interested in that. 1113 01:05:42,910 --> 01:05:46,200 So I'm only going to write this if status 1114 01:05:46,200 --> 01:05:48,150 did just finish part of the code. 1115 01:05:48,150 --> 01:05:51,520 And I'm just gonna have this function do nothing otherwise. 1116 01:05:51,520 --> 01:05:56,010 What we want to do here is we want to kind of reset the video. 1117 01:05:56,010 --> 01:06:09,960 So reset async equals async function that says if this video-- 1118 01:06:09,960 --> 01:06:12,790 we're going to say await this.video. 1119 01:06:12,790 --> 01:06:14,810 Stop async. 1120 01:06:14,810 --> 01:06:23,664 If I look at the video API, I can see that I can call stop async on it, 1121 01:06:23,664 --> 01:06:25,080 which does what you think it does. 1122 01:06:25,080 --> 01:06:28,260 It just stops the video. 1123 01:06:28,260 --> 01:06:34,111 And then I'm going to say set position async to zero, 1124 01:06:34,111 --> 01:06:35,610 which is the beginning of the video. 1125 01:06:35,610 --> 01:06:38,370 Because set position async takes one parameter 1126 01:06:38,370 --> 01:06:41,660 that's a number of milliseconds into the video to play from. 1127 01:06:41,660 --> 01:06:43,230 So zero is the very beginning. 1128 01:06:43,230 --> 01:06:48,720 The reason I have to call stop async is that if I just call 1129 01:06:48,720 --> 01:06:53,370 set position async at the end of the video playing, 1130 01:06:53,370 --> 01:06:54,940 on either Android or iOS-- 1131 01:06:54,940 --> 01:06:56,100 I forget which one-- 1132 01:06:56,100 --> 01:07:00,360 the video is actually not fully stopped playing when didJustFinish fires. 1133 01:07:00,360 --> 01:07:01,967 And so it'll reset the position. 1134 01:07:01,967 --> 01:07:04,050 And it'll think, oh, I still have a bunch to play. 1135 01:07:04,050 --> 01:07:05,800 And it'll continue playing in a loop. 1136 01:07:05,800 --> 01:07:10,650 So I'm gonna call stop just to make sure that doesn't happen and be safe. 1137 01:07:10,650 --> 01:07:13,170 1138 01:07:13,170 --> 01:07:20,875 So now if I call this here, then if I just say this reset async 1139 01:07:20,875 --> 01:07:23,994 and save that, then now the video should play, 1140 01:07:23,994 --> 01:07:26,160 and then it should go back to the first frame, where 1141 01:07:26,160 --> 01:07:27,493 you sort of see that smiley cat. 1142 01:07:27,493 --> 01:07:30,460 1143 01:07:30,460 --> 01:07:31,900 And there we go. 1144 01:07:31,900 --> 01:07:35,290 You can't see his face, but the cat's back. 1145 01:07:35,290 --> 01:07:41,050 So now what I want to do is make it so when I touch this, it plays that again. 1146 01:07:41,050 --> 01:07:44,940 So now I'm going to have to put some sort of touchable area on it. 1147 01:07:44,940 --> 01:07:49,750 So I'm gonna add touchable highlight here of the things that I import. 1148 01:07:49,750 --> 01:07:56,800 And I'm gonna say this is a view that's wrapping this. 1149 01:07:56,800 --> 01:08:02,065 And then I'm gonna say view here. 1150 01:08:02,065 --> 01:08:05,000 1151 01:08:05,000 --> 01:08:07,320 And then I'm gonna use a touchable highlight here. 1152 01:08:07,320 --> 01:08:10,130 1153 01:08:10,130 --> 01:08:13,490 The reason for this inner view is that touchable highlights and things 1154 01:08:13,490 --> 01:08:18,229 like that need, like, a React Native view and not an Expo video 1155 01:08:18,229 --> 01:08:23,939 view because they get confused about refs and things like that. 1156 01:08:23,939 --> 01:08:28,910 So that's just a general thing, is if weird things are breaking around 1157 01:08:28,910 --> 01:08:32,390 touchable highlight or very native components like video players 1158 01:08:32,390 --> 01:08:36,569 and things like that, then just try adding in intermediate views. 1159 01:08:36,569 --> 01:08:39,899 And that might fix your problems in some cases. 1160 01:08:39,899 --> 01:08:42,710 So now I'm just going to capture the presses here 1161 01:08:42,710 --> 01:08:48,319 on this touchable highlight area, and then just say-- 1162 01:08:48,319 --> 01:08:53,569 I'm gonna log that press the cat. 1163 01:08:53,569 --> 01:08:55,310 So I can just test this. 1164 01:08:55,310 --> 01:08:56,689 OK. 1165 01:08:56,689 --> 01:08:59,226 So now it's downloading. 1166 01:08:59,226 --> 01:09:05,635 1167 01:09:05,635 --> 01:09:08,270 And I can see as I press it, the highlight shows up. 1168 01:09:08,270 --> 01:09:10,130 But let me just make sure that that-- 1169 01:09:10,130 --> 01:09:11,149 yep. 1170 01:09:11,149 --> 01:09:15,620 The log that says press the cat shows up every time I press it. 1171 01:09:15,620 --> 01:09:18,529 And so now I just have to make it play again. 1172 01:09:18,529 --> 01:09:24,920 So now I'm just gonna add another method called playAsync. 1173 01:09:24,920 --> 01:09:41,080 And it's gonna say await this.video.replayAsync, which is 1174 01:09:41,080 --> 01:09:44,200 documented in the AV function, I guess. 1175 01:09:44,200 --> 01:09:48,670 1176 01:09:48,670 --> 01:09:53,439 But basically, this will replay the item from position zero. 1177 01:09:53,439 --> 01:09:55,700 So that's a pretty good thing to use. 1178 01:09:55,700 --> 01:10:04,060 So now we'll just say when you press this, instead of logging 1179 01:10:04,060 --> 01:10:08,470 that, I'm going to say this.playAsync. 1180 01:10:08,470 --> 01:10:09,850 Cool. 1181 01:10:09,850 --> 01:10:21,852 So now if I go look at this, once this loads, now when I press it, 1182 01:10:21,852 --> 01:10:22,810 it should replay again. 1183 01:10:22,810 --> 01:10:26,350 So I can just keep doing this over and over and over again. 1184 01:10:26,350 --> 01:10:28,217 1185 01:10:28,217 --> 01:10:31,300 And if I press in the middle of it playing, it'll go back to the beginning 1186 01:10:31,300 --> 01:10:32,990 and play it then. 1187 01:10:32,990 --> 01:10:33,520 Cool. 1188 01:10:33,520 --> 01:10:36,370 So now I just have to put together a whole bunch of these. 1189 01:10:36,370 --> 01:10:40,210 But before I do that, I kind of want to make this look a little better. 1190 01:10:40,210 --> 01:10:45,234 So what I'm actually going to do is say-- 1191 01:10:45,234 --> 01:10:46,900 let's make the background of this green. 1192 01:10:46,900 --> 01:10:52,120 So I'm gonna change this background color from FFF to green. 1193 01:10:52,120 --> 01:11:05,330 And I'm gonna change this text color here to yellow. 1194 01:11:05,330 --> 01:11:08,792 And I'm gonna make it kind of big. 1195 01:11:08,792 --> 01:11:11,066 And let's see how that looks. 1196 01:11:11,066 --> 01:11:15,900 1197 01:11:15,900 --> 01:11:16,400 OK. 1198 01:11:16,400 --> 01:11:18,600 That looks a little bit interesting. 1199 01:11:18,600 --> 01:11:22,100 But I kind of want a different font because I don't like the way 1200 01:11:22,100 --> 01:11:24,530 that font looks with this color scheme. 1201 01:11:24,530 --> 01:11:26,780 So the way I can use different fonts is I can actually 1202 01:11:26,780 --> 01:11:33,440 use, like, files like TTF files or OTF files as custom fonts 1203 01:11:33,440 --> 01:11:37,200 that I can just load into the app on the fly. 1204 01:11:37,200 --> 01:11:40,130 So let's do that now. 1205 01:11:40,130 --> 01:11:44,750 So I sort of showed you that I put in some mp4 files. 1206 01:11:44,750 --> 01:11:48,306 I also put in this Cooper Black Regular font. 1207 01:11:48,306 --> 01:11:51,230 You can just take a look at what that looks like in this preview. 1208 01:11:51,230 --> 01:11:52,860 It looks like this. 1209 01:11:52,860 --> 01:11:55,100 That's pretty nice-looking. 1210 01:11:55,100 --> 01:11:59,600 So to use that, what we have to do is we have to load in the font to begin with. 1211 01:11:59,600 --> 01:12:06,050 So we're going to make a method that loads in these fonts. 1212 01:12:06,050 --> 01:12:07,550 And that's pretty easy. 1213 01:12:07,550 --> 01:12:10,810 You just do Expo.font.loadAsyn. 1214 01:12:10,810 --> 01:12:12,380 And then it takes a map. 1215 01:12:12,380 --> 01:12:17,970 And you can just say Cooper Black Regular require 1216 01:12:17,970 --> 01:12:23,630 assets CooperBlackRegular.TTF And then this 1217 01:12:23,630 --> 01:12:35,120 will load that font into the font sort of dictionary 1218 01:12:35,120 --> 01:12:37,340 under Cooper Black Regular. 1219 01:12:37,340 --> 01:12:40,370 But to have it render properly, we have to have the font loaded 1220 01:12:40,370 --> 01:12:42,260 before we show this text. 1221 01:12:42,260 --> 01:12:46,130 So we're going to use a technique where we use state 1222 01:12:46,130 --> 01:12:48,180 to keep track of whether it's loaded or not. 1223 01:12:48,180 --> 01:12:51,770 So we're going to say IsReady false here in state. 1224 01:12:51,770 --> 01:12:57,500 And then in this render method of this whole thing, 1225 01:12:57,500 --> 01:13:11,940 I'm going to say if not this.state is ready, return Expo.AppLoading. 1226 01:13:11,940 --> 01:13:15,410 This app loading thing is just like sort of a splash screen that 1227 01:13:15,410 --> 01:13:17,750 will show until your app is loaded. 1228 01:13:17,750 --> 01:13:24,579 And so this is just a convenience way to show something that looks like your app 1229 01:13:24,579 --> 01:13:25,620 while it's getting ready. 1230 01:13:25,620 --> 01:13:29,340 Like, if I switch into something like Facebook, 1231 01:13:29,340 --> 01:13:33,094 you can see for a split second, it shows the scaffolding of Facebook. 1232 01:13:33,094 --> 01:13:35,510 Same thing if I go into, like, Yelp will probably do that. 1233 01:13:35,510 --> 01:13:38,120 Yelp just shows the Yelp logo and a red screen. 1234 01:13:38,120 --> 01:13:40,190 So the app-loading container is basically just 1235 01:13:40,190 --> 01:13:43,846 a way to show something like that, which you can configure in your app.json 1236 01:13:43,846 --> 01:13:44,720 and things like that. 1237 01:13:44,720 --> 01:13:49,150 But we're just going to show that until the font is ready. 1238 01:13:49,150 --> 01:13:53,540 So that'll execute when the state is not ready. 1239 01:13:53,540 --> 01:13:56,690 But the rest of the time, we'll render the video board. 1240 01:13:56,690 --> 01:14:00,490 So now we have multiple things to do before everything works. 1241 01:14:00,490 --> 01:14:06,060 So we're going to say await promise.all. 1242 01:14:06,060 --> 01:14:08,930 this.set.AudioModeAsync. 1243 01:14:08,930 --> 01:14:10,275 this.loadFontsAsync. 1244 01:14:10,275 --> 01:14:12,920 1245 01:14:12,920 --> 01:14:15,410 And then once those are done, now I'm going to-- 1246 01:14:15,410 --> 01:14:18,847 1247 01:14:18,847 --> 01:14:20,562 I have to put this into an async method. 1248 01:14:20,562 --> 01:14:25,954 1249 01:14:25,954 --> 01:14:26,454 Whoops. 1250 01:14:26,454 --> 01:14:38,750 1251 01:14:38,750 --> 01:14:44,500 Then I can say this.setState is ready, true. 1252 01:14:44,500 --> 01:14:46,930 So it's going to set up the audio mode and load the fonts, 1253 01:14:46,930 --> 01:14:52,150 and then it should be ready. 1254 01:14:52,150 --> 01:14:54,330 So then-- OK. 1255 01:14:54,330 --> 01:14:55,330 Let's see if this works. 1256 01:14:55,330 --> 01:15:01,230 1257 01:15:01,230 --> 01:15:02,610 Everything seems in order. 1258 01:15:02,610 --> 01:15:05,400 But now I have to actually use the font that I set up 1259 01:15:05,400 --> 01:15:06,550 instead of just loading it. 1260 01:15:06,550 --> 01:15:14,340 So I'm going to say fontFamily Cooper Black Regular. 1261 01:15:14,340 --> 01:15:16,530 And let's see if that works. 1262 01:15:16,530 --> 01:15:18,780 Now this should not display until the font is actually 1263 01:15:18,780 --> 01:15:20,436 loaded into the program's memory. 1264 01:15:20,436 --> 01:15:26,760 1265 01:15:26,760 --> 01:15:27,720 Bam. 1266 01:15:27,720 --> 01:15:30,530 So now this looks basically right. 1267 01:15:30,530 --> 01:15:34,950 But you can also see that the cat sounds thing showed up, 1268 01:15:34,950 --> 01:15:38,190 but then it took a little while for the video to show up. 1269 01:15:38,190 --> 01:15:43,530 And so we can actually preload the videos, as well, 1270 01:15:43,530 --> 01:15:47,590 and make sure that they're loaded in, as well. 1271 01:15:47,590 --> 01:15:52,880 So we can say, like, load videos async. 1272 01:15:52,880 --> 01:15:56,800 1273 01:15:56,800 --> 01:16:04,370 We'll say and await Expo.asset.loadAsync. 1274 01:16:04,370 --> 01:16:07,760 1275 01:16:07,760 --> 01:16:15,900 And then basically, you can just pass in a bunch of require things in here, 1276 01:16:15,900 --> 01:16:16,560 and it'll work. 1277 01:16:16,560 --> 01:16:19,482 1278 01:16:19,482 --> 01:16:22,740 And this will load these, and then return 1279 01:16:22,740 --> 01:16:27,596 when they're all loaded or basically downloaded from the internet or ready. 1280 01:16:27,596 --> 01:16:31,862 1281 01:16:31,862 --> 01:16:34,570 The way that Expo works is that everything is loaded over the air 1282 01:16:34,570 --> 01:16:36,250 so that you can load things like-- 1283 01:16:36,250 --> 01:16:38,620 you can make changes to your app without resubmitting 1284 01:16:38,620 --> 01:16:40,000 a binary, et cetera, et cetera. 1285 01:16:40,000 --> 01:16:44,740 And so all assets work either when they're already on the device 1286 01:16:44,740 --> 01:16:45,830 or when they're not. 1287 01:16:45,830 --> 01:16:49,090 And so this load async thing will make sure all of these things 1288 01:16:49,090 --> 01:16:54,376 are downloaded from the internet before it fires. 1289 01:16:54,376 --> 01:16:56,840 So I'm gonna say seven, eight, nine. 1290 01:16:56,840 --> 01:17:03,090 And so then in setup, I'm gonna say I want to load assets, as well. 1291 01:17:03,090 --> 01:17:09,590 1292 01:17:09,590 --> 01:17:12,210 So now we'll do all these steps before it says it's ready. 1293 01:17:12,210 --> 01:17:16,020 And so there's still another step, even after the video's downloaded, 1294 01:17:16,020 --> 01:17:19,040 of getting it prepared to show on the screen and stuff like that. 1295 01:17:19,040 --> 01:17:21,060 So it won't be totally instant, but it should 1296 01:17:21,060 --> 01:17:26,587 be a little bit snappier and a little bit less janky when I do this now. 1297 01:17:26,587 --> 01:17:39,010 1298 01:17:39,010 --> 01:17:39,510 OK. 1299 01:17:39,510 --> 01:17:44,100 Now I'm just gonna add, like, nine of these. 1300 01:17:44,100 --> 01:17:47,432 1301 01:17:47,432 --> 01:17:50,220 flexDirection row. 1302 01:17:50,220 --> 01:17:51,420 Put three of these in a row. 1303 01:17:51,420 --> 01:17:57,340 1304 01:17:57,340 --> 01:18:00,130 And I'm gonna make this two and three. 1305 01:18:00,130 --> 01:18:06,512 And then I'm actually going to add a margin here, I think. 1306 01:18:06,512 --> 01:18:25,852 1307 01:18:25,852 --> 01:18:26,352 Come on. 1308 01:18:26,352 --> 01:18:29,830 1309 01:18:29,830 --> 01:18:31,760 So now I have three videos all going at once. 1310 01:18:31,760 --> 01:18:35,244 But they're all squinched together, so that's why I'm adding this margin. 1311 01:18:35,244 --> 01:18:37,160 So now that basically seems like it's working. 1312 01:18:37,160 --> 01:18:38,785 So I'm gonna just format this. 1313 01:18:38,785 --> 01:18:42,570 And I'm gonna copy this three times so I can just add the other videos. 1314 01:18:42,570 --> 01:18:55,310 1315 01:18:55,310 --> 01:19:07,275 Now I should have a fully-functioning video board, if I'm not mistaken. 1316 01:19:07,275 --> 01:19:11,350 1317 01:19:11,350 --> 01:19:15,960 So now whenever I tap any of these things, they should work. 1318 01:19:15,960 --> 01:19:16,460 And-- 1319 01:19:16,460 --> 01:19:18,216 [MUSIC PLAYING] 1320 01:19:18,216 --> 01:19:18,715 1321 01:19:18,715 --> 01:19:23,090 I can make all kinds of funny noises and things like that. 1322 01:19:23,090 --> 01:19:24,630 Cool. 1323 01:19:24,630 --> 01:19:27,980 Well, I think if you run this on older Androids, or actually a lot different 1324 01:19:27,980 --> 01:19:31,110 Androids, sometimes having nine different videos on the screen at once 1325 01:19:31,110 --> 01:19:32,070 will overwhelm it. 1326 01:19:32,070 --> 01:19:35,620 I think that the video library can probably 1327 01:19:35,620 --> 01:19:38,250 be improved to make that not blow things up. 1328 01:19:38,250 --> 01:19:41,880 But in the short term, you probably need to make this only a three-entry video 1329 01:19:41,880 --> 01:19:45,941 board or something to have it work on Android, unfortunately. 1330 01:19:45,941 --> 01:19:46,440 Cool. 1331 01:19:46,440 --> 01:19:50,490 1332 01:19:50,490 --> 01:19:53,850 You can also do stuff with sounds instead of just videos. 1333 01:19:53,850 --> 01:19:55,710 I won't show that here. 1334 01:19:55,710 --> 01:20:00,480 But the methods and everything for dealing with sounds and videos 1335 01:20:00,480 --> 01:20:03,540 are very similar in Expo. 1336 01:20:03,540 --> 01:20:05,550 The same person made both of those things, 1337 01:20:05,550 --> 01:20:07,720 and tried to make the APIs as similar as possible. 1338 01:20:07,720 --> 01:20:11,190 So things like replayAsync and stopAsync and those kind of methods all work. 1339 01:20:11,190 --> 01:20:11,730 1340 01:20:11,730 --> 01:20:15,270 The main difference is that you end up, like-- 1341 01:20:15,270 --> 01:20:19,030 there isn't, like, a visual manifestation of the sound component. 1342 01:20:19,030 --> 01:20:21,600 You just have an abstract object in JavaScript memory 1343 01:20:21,600 --> 01:20:27,300 that you control, sort of similar to the [? this.underscoreVideo ?] reference 1344 01:20:27,300 --> 01:20:34,860 that we ended up making by doing the ref thing here. 1345 01:20:34,860 --> 01:20:37,570 But sound is basically just as easy. 1346 01:20:37,570 --> 01:20:43,830 So what I'm gonna show next is I'm gonna try to do a little bit of stuff 1347 01:20:43,830 --> 01:20:44,430 with photos. 1348 01:20:44,430 --> 01:20:47,090 1349 01:20:47,090 --> 01:20:52,080 So I'm go back into doing a Snack for that. 1350 01:20:52,080 --> 01:21:01,880 1351 01:21:01,880 --> 01:21:03,840 And minimize this. 1352 01:21:03,840 --> 01:21:09,720 1353 01:21:09,720 --> 01:21:12,470 [? This next one. ?] 1354 01:21:12,470 --> 01:21:17,720 And then there's a couple different ways you can do photos. 1355 01:21:17,720 --> 01:21:22,070 I'm gonna do the same thing here, where I import from Expo. 1356 01:21:22,070 --> 01:21:23,027 Get rid of this stuff. 1357 01:21:23,027 --> 01:21:28,871 1358 01:21:28,871 --> 01:21:35,340 And then get rid of that. 1359 01:21:35,340 --> 01:21:35,950 OK. 1360 01:21:35,950 --> 01:21:52,980 So now I can do something where I use the camera roll on the camera. 1361 01:21:52,980 --> 01:21:55,440 So the first thing I'm gonna do is just show an image, 1362 01:21:55,440 --> 01:21:58,810 just because that's a good starting point. 1363 01:21:58,810 --> 01:22:04,100 So I'm going to just-- 1364 01:22:04,100 --> 01:22:04,710 let's see. 1365 01:22:04,710 --> 01:22:19,420 I'm gonna take these dogs. 1366 01:22:19,420 --> 01:22:25,330 And I'm gonna do view style equals flexDirection row. 1367 01:22:25,330 --> 01:22:29,715 1368 01:22:29,715 --> 01:22:32,440 Image source equals require. 1369 01:22:32,440 --> 01:22:37,396 1370 01:22:37,396 --> 01:22:37,896 Enable. 1371 01:22:37,896 --> 01:22:57,260 1372 01:22:57,260 --> 01:22:57,760 OK. 1373 01:22:57,760 --> 01:23:00,242 1374 01:23:00,242 --> 01:23:00,950 Unexpected token. 1375 01:23:00,950 --> 01:23:12,518 1376 01:23:12,518 --> 01:23:13,470 Hmm. 1377 01:23:13,470 --> 01:23:13,970 OK. 1378 01:23:13,970 --> 01:23:19,240 So now I have two pictures of dogs here that I'm just gonna put in place just 1379 01:23:19,240 --> 01:23:21,220 to start playing around with photos. 1380 01:23:21,220 --> 01:23:26,550 1381 01:23:26,550 --> 01:23:30,600 And now I'm gonna launch the camera roll. 1382 01:23:30,600 --> 01:23:33,520 I'm going to make a method called launchCameraRollAsync. 1383 01:23:33,520 --> 01:23:36,570 1384 01:23:36,570 --> 01:23:39,600 And I'm gonna look up in the docs how to do that. 1385 01:23:39,600 --> 01:23:42,540 I'm gonna use something called image picker. 1386 01:23:42,540 --> 01:23:46,350 To deal with images and the camera and those kind of things in Expo, 1387 01:23:46,350 --> 01:23:49,470 there's kind of two layers of stuff. 1388 01:23:49,470 --> 01:23:51,360 There's one thing called image picker, which 1389 01:23:51,360 --> 01:23:54,510 gives you a really simple kind of full-featured way 1390 01:23:54,510 --> 01:23:56,970 to access the camera roll or the camera. 1391 01:23:56,970 --> 01:24:00,452 But it's full-featured, but not customizable at all. 1392 01:24:00,452 --> 01:24:02,910 So I'm gonna show you how to use-- or that's not 100% true. 1393 01:24:02,910 --> 01:24:04,952 But only in very limited ways is it customizable. 1394 01:24:04,952 --> 01:24:07,160 So if you're trying to build something really, really 1395 01:24:07,160 --> 01:24:10,120 quickly or just prototype something, or you just have very basic needs, 1396 01:24:10,120 --> 01:24:12,780 this can be really useful and easy and quick. 1397 01:24:12,780 --> 01:24:14,700 But if you wanted to make something where 1398 01:24:14,700 --> 01:24:19,260 the camera is a big focus of the app, or you want to customize the way that it 1399 01:24:19,260 --> 01:24:24,810 works or things like that, you'll need to use the camera component 1400 01:24:24,810 --> 01:24:28,230 or write your own camera roll component. 1401 01:24:28,230 --> 01:24:31,014 And so I'm just gonna show this image picker thing first, which 1402 01:24:31,014 --> 01:24:32,430 a lot of people might find useful. 1403 01:24:32,430 --> 01:24:36,540 And then I'll go into a little bit on the camera stuff. 1404 01:24:36,540 --> 01:24:39,410 So there's two main things that image picker 1405 01:24:39,410 --> 01:24:44,580 has-- launch image library async, and then launch camera async. 1406 01:24:44,580 --> 01:24:56,490 I'll do both of them, but we'll start with the launch image library async. 1407 01:24:56,490 --> 01:24:58,830 We need to ask for permission first. 1408 01:24:58,830 --> 01:25:01,040 So same thing as we've done a bunch of times before. 1409 01:25:01,040 --> 01:25:05,280 We'll say await expo permissions. 1410 01:25:05,280 --> 01:25:10,140 Ask async Expo.permissions.cameraRoll. 1411 01:25:10,140 --> 01:25:15,990 1412 01:25:15,990 --> 01:25:21,490 And let status equal await that. 1413 01:25:21,490 --> 01:25:35,280 If status isn't granted, then we'll just bail. 1414 01:25:35,280 --> 01:25:40,350 But otherwise, we'll say Expo ImagePicker launch-- 1415 01:25:40,350 --> 01:25:41,490 what was the name of that? 1416 01:25:41,490 --> 01:25:42,772 Launch image library async. 1417 01:25:42,772 --> 01:25:46,882 1418 01:25:46,882 --> 01:25:49,090 And so right now, we'll just launch the image picker. 1419 01:25:49,090 --> 01:25:52,408 We won't even do anything with the result. Maybe I'll await it. 1420 01:25:52,408 --> 01:25:59,832 1421 01:25:59,832 --> 01:26:00,915 And then I'll just log it. 1422 01:26:00,915 --> 01:26:05,010 1423 01:26:05,010 --> 01:26:08,550 So now let's make a button that launches this. 1424 01:26:08,550 --> 01:26:13,860 So we'll say stick a button here. 1425 01:26:13,860 --> 01:26:16,640 Launch camera roll. 1426 01:26:16,640 --> 01:26:26,130 On press equals-- and we need an import button. 1427 01:26:26,130 --> 01:26:28,620 So we'll go back down here. 1428 01:26:28,620 --> 01:26:32,070 And here I'm just going to say this.launchCameraRollAsync. 1429 01:26:32,070 --> 01:26:33,390 Cool. 1430 01:26:33,390 --> 01:26:35,530 And hit the prettier button. 1431 01:26:35,530 --> 01:26:38,410 1432 01:26:38,410 --> 01:26:43,810 So now when I tap this-- 1433 01:26:43,810 --> 01:26:44,310 whoa. 1434 01:26:44,310 --> 01:26:45,270 What'd I do? 1435 01:26:45,270 --> 01:26:49,110 1436 01:26:49,110 --> 01:26:50,550 OK. 1437 01:26:50,550 --> 01:26:52,950 When I tap this, I should get something logged. 1438 01:26:52,950 --> 01:26:58,240 1439 01:26:58,240 --> 01:26:59,300 Cool. 1440 01:26:59,300 --> 01:27:07,420 So now I can look at all these different things and choose one of them. 1441 01:27:07,420 --> 01:27:12,230 1442 01:27:12,230 --> 01:27:13,480 But now how can I show that? 1443 01:27:13,480 --> 01:27:18,852 1444 01:27:18,852 --> 01:27:21,670 I'm gonna change this to await this because it's an async thing, 1445 01:27:21,670 --> 01:27:24,910 and this is just what a promise looks like when you log it. 1446 01:27:24,910 --> 01:27:27,290 So now I'm gonna do this again. 1447 01:27:27,290 --> 01:27:29,600 I'm gonna pick a moment. 1448 01:27:29,600 --> 01:27:32,930 And now I can see I get this object back that has a bunch of metadata. 1449 01:27:32,930 --> 01:27:36,130 It has a URI, which is a local file, and then has 1450 01:27:36,130 --> 01:27:39,410 a type image, canceled false, and then a width and a height. 1451 01:27:39,410 --> 01:27:40,420 So that's pretty easy. 1452 01:27:40,420 --> 01:27:46,130 So I'm just gonna say-- let's add a state thing here. 1453 01:27:46,130 --> 01:27:48,620 Equals chosen image. 1454 01:27:48,620 --> 01:27:50,830 We'll say it's null to begin with. 1455 01:27:50,830 --> 01:28:00,520 And then after this camera roll thing, I'll say this.state.chosenImage, 1456 01:28:00,520 --> 01:28:06,610 if it's true-ish, then we'll say-- let's put an image here. 1457 01:28:06,610 --> 01:28:10,340 And we'll say the source is this.state.chosenImage.uri. 1458 01:28:10,340 --> 01:28:17,420 1459 01:28:17,420 --> 01:28:20,390 And the style will be-- 1460 01:28:20,390 --> 01:28:23,244 1461 01:28:23,244 --> 01:28:25,160 well, we could use the height and width of it. 1462 01:28:25,160 --> 01:28:27,076 Or we could just make it something reasonable. 1463 01:28:27,076 --> 01:28:32,100 So we'll just say height 200, width 200 so it doesn't get too, too big 1464 01:28:32,100 --> 01:28:36,080 or take it over, or null. 1465 01:28:36,080 --> 01:28:38,020 OK. 1466 01:28:38,020 --> 01:28:46,930 So now if I launch the camera roll and choose this picture of me and Nicky, 1467 01:28:46,930 --> 01:28:50,090 then-- oh, I forgot to set state. 1468 01:28:50,090 --> 01:28:58,962 Instead of logging this, I'm gonna say this set state chosen image is image. 1469 01:28:58,962 --> 01:29:04,380 1470 01:29:04,380 --> 01:29:04,880 OK. 1471 01:29:04,880 --> 01:29:11,780 So now if I launch camera roll and choose Nicky, now that shows up here. 1472 01:29:11,780 --> 01:29:14,620 Cool. 1473 01:29:14,620 --> 01:29:21,259 And so then what I can do is now I can use the launch camera async 1474 01:29:21,259 --> 01:29:21,800 if I want to. 1475 01:29:21,800 --> 01:29:24,850 1476 01:29:24,850 --> 01:29:28,490 So let's make another-- let's shrink this down so I can actually see stuff. 1477 01:29:28,490 --> 01:29:38,390 Let's put another button in here that's like button title equals launch camera. 1478 01:29:38,390 --> 01:29:44,362 So when you press this, it's gonna call this.launchCameraAsync. 1479 01:29:44,362 --> 01:29:51,610 1480 01:29:51,610 --> 01:29:55,300 So now I have to write this method. 1481 01:29:55,300 --> 01:29:56,943 So launchCameraAsync. 1482 01:29:56,943 --> 01:30:00,647 1483 01:30:00,647 --> 01:30:02,260 Do the permissions thing again. 1484 01:30:02,260 --> 01:30:04,640 I'll just copy and paste from here. 1485 01:30:04,640 --> 01:30:07,640 We actually need different permissions because it's not the camera roll, 1486 01:30:07,640 --> 01:30:09,800 but we actually need the camera. 1487 01:30:09,800 --> 01:30:13,040 So I'll just change this. 1488 01:30:13,040 --> 01:30:16,190 But otherwise, this code is the same. 1489 01:30:16,190 --> 01:30:22,730 And then instead of the image being from image picker launch image 1490 01:30:22,730 --> 01:30:30,730 library async, it's going to be from image picker, launchCameraAsync. 1491 01:30:30,730 --> 01:30:33,970 So I'm gonna call that. 1492 01:30:33,970 --> 01:30:40,040 And take an image. 1493 01:30:40,040 --> 01:30:42,830 1494 01:30:42,830 --> 01:30:44,400 OK. 1495 01:30:44,400 --> 01:30:49,230 So now if I hit launch camera, now I have a camera. 1496 01:30:49,230 --> 01:30:52,260 So I can see the handful of you who are here in the audience, 1497 01:30:52,260 --> 01:30:57,060 or I can flip the camera around and see myself. 1498 01:30:57,060 --> 01:30:58,440 Cool. 1499 01:30:58,440 --> 01:31:00,040 So I take a photo. 1500 01:31:00,040 --> 01:31:02,290 And it'll give me a chance to retake or use the photo. 1501 01:31:02,290 --> 01:31:04,410 And I can say use photo. 1502 01:31:04,410 --> 01:31:07,410 Now we just did set state, but we don't do anything with that image yet. 1503 01:31:07,410 --> 01:31:09,618 So one thing you can control here is there's actually 1504 01:31:09,618 --> 01:31:12,040 a couple of options that are sort of interesting here. 1505 01:31:12,040 --> 01:31:13,960 One of them is allows editing. 1506 01:31:13,960 --> 01:31:25,200 If I turn on allows editing, I can actually modify this. 1507 01:31:25,200 --> 01:31:29,565 So I can, like, zoom and crop and stuff in different ways. 1508 01:31:29,565 --> 01:31:30,690 So that's sometimes useful. 1509 01:31:30,690 --> 01:31:33,620 1510 01:31:33,620 --> 01:31:43,000 But now I'm going to basically copy this code here and put the same thing in, 1511 01:31:43,000 --> 01:31:45,890 except I'm going to choose taken image instead of chosen image. 1512 01:31:45,890 --> 01:31:50,345 1513 01:31:50,345 --> 01:31:50,850 Oops. 1514 01:31:50,850 --> 01:31:54,270 1515 01:31:54,270 --> 01:31:57,320 So now when I launch this, and I'm gonna take a picture of me. 1516 01:31:57,320 --> 01:31:59,984 1517 01:31:59,984 --> 01:32:01,090 Do that. 1518 01:32:01,090 --> 01:32:02,190 Now that shows up here. 1519 01:32:02,190 --> 01:32:05,920 So now I've gotten an image from the camera and stored it here. 1520 01:32:05,920 --> 01:32:08,532 One thing that you might notice is to me, 1521 01:32:08,532 --> 01:32:10,240 this probably looks like a normal selfie. 1522 01:32:10,240 --> 01:32:14,170 But it actually looks really weird to me because I look like I'm-- 1523 01:32:14,170 --> 01:32:20,320 like when I watch closely, you'll see that when the camera's open, 1524 01:32:20,320 --> 01:32:22,150 it sort of looks like a mirror to me. 1525 01:32:22,150 --> 01:32:24,580 But then when it actually returns the photo, 1526 01:32:24,580 --> 01:32:26,950 it sort of flipped, which is disorienting 1527 01:32:26,950 --> 01:32:28,510 if you're taking the photo. 1528 01:32:28,510 --> 01:32:29,430 So I kind of like-- 1529 01:32:29,430 --> 01:32:33,170 1530 01:32:33,170 --> 01:32:35,650 I'll unbutton my sweatshirt, and you can see 1531 01:32:35,650 --> 01:32:39,450 that "I took CS50" is backwards in the view that I'm seeing. 1532 01:32:39,450 --> 01:32:43,780 But here when I take this picture, now it looks readable. 1533 01:32:43,780 --> 01:32:47,110 And so we actually want it to be the other way around, 1534 01:32:47,110 --> 01:32:48,687 I think, for a lot of applications. 1535 01:32:48,687 --> 01:32:51,270 Sometimes you might not want to, but sometimes you do want to. 1536 01:32:51,270 --> 01:32:53,500 But let's just practice flipping it around because it's sort of a thing 1537 01:32:53,500 --> 01:32:57,280 that you commonly want to do, especially when you're using the selfie camera. 1538 01:32:57,280 --> 01:33:01,360 And the way we can do that is something called image manipulation. 1539 01:33:01,360 --> 01:33:04,780 There's an Expo module called image manipulator. 1540 01:33:04,780 --> 01:33:08,560 And so it takes an array of actions-- 1541 01:33:08,560 --> 01:33:11,515 resize, rotate, flip, crop, et cetera. 1542 01:33:11,515 --> 01:33:15,170 What we're going to want to do is the flip horizontal. 1543 01:33:15,170 --> 01:33:23,989 And so I can take this thing after this. 1544 01:33:23,989 --> 01:33:25,530 We'll just assume we want to do this. 1545 01:33:25,530 --> 01:33:34,460 And we'll say let flippedImage equals await Expo.ImageManipulator. 1546 01:33:34,460 --> 01:33:37,550 1547 01:33:37,550 --> 01:33:41,510 And then manipulate. 1548 01:33:41,510 --> 01:33:44,160 And then the first argument is the URI. 1549 01:33:44,160 --> 01:33:47,450 And so it's just going to be image.uri. 1550 01:33:47,450 --> 01:33:52,100 And then the actions, it's an array. 1551 01:33:52,100 --> 01:33:55,115 And the first thing we want it to do is flip. 1552 01:33:55,115 --> 01:33:58,460 1553 01:33:58,460 --> 01:34:05,510 And it takes vertical and horizontal properties. 1554 01:34:05,510 --> 01:34:12,210 And we want vertical to be false and horizontal to be true. 1555 01:34:12,210 --> 01:34:19,460 And so then save options is the last argument here. 1556 01:34:19,460 --> 01:34:25,280 And we can probably just leave this as the default. 1557 01:34:25,280 --> 01:34:28,670 So now we'll say whatever the result of that 1558 01:34:28,670 --> 01:34:31,530 is, we'll pass that to take an image. 1559 01:34:31,530 --> 01:34:36,990 So now when I go here, when I launch the camera, 1560 01:34:36,990 --> 01:34:39,260 I'll turn it around to do the selfie thing. 1561 01:34:39,260 --> 01:34:44,125 And then you can see that this is backwards here, not really readable. 1562 01:34:44,125 --> 01:34:45,000 I'll take this photo. 1563 01:34:45,000 --> 01:34:51,230 1564 01:34:51,230 --> 01:34:59,170 And now-- oh, there's something where it's now been flipped vertically 1565 01:34:59,170 --> 01:35:00,890 for some reason. 1566 01:35:00,890 --> 01:35:05,290 So let's just play around with these options 1567 01:35:05,290 --> 01:35:07,430 and try to figure out why that is. 1568 01:35:07,430 --> 01:35:10,820 1569 01:35:10,820 --> 01:35:16,160 Sometimes there's quirky things with cameras on certain devices. 1570 01:35:16,160 --> 01:35:18,580 Hmm. 1571 01:35:18,580 --> 01:35:26,486 I'm super confused about why this is not flipping this the right way. 1572 01:35:26,486 --> 01:35:30,270 I think it should. 1573 01:35:30,270 --> 01:35:32,826 Well, I don't know. 1574 01:35:32,826 --> 01:35:34,700 Sometimes you end up with upside-down images. 1575 01:35:34,700 --> 01:35:37,533 And this is the real world of dealing with actual devices and things 1576 01:35:37,533 --> 01:35:38,770 like that. 1577 01:35:38,770 --> 01:35:42,670 But that is how you flip an image. 1578 01:35:42,670 --> 01:35:43,227 Cool. 1579 01:35:43,227 --> 01:35:45,310 So just because we don't have that much time left, 1580 01:35:45,310 --> 01:35:48,430 I'm going to jump right into using the actual camera component that's 1581 01:35:48,430 --> 01:35:50,422 much more customizable. 1582 01:35:50,422 --> 01:36:00,260 And so we basically need to do the same thing where we 1583 01:36:00,260 --> 01:36:03,256 get permissions for the camera again. 1584 01:36:03,256 --> 01:36:09,110 So we'll just copy this code. 1585 01:36:09,110 --> 01:36:13,812 And we'll make another thing that's like launchCustomCameraAsync. 1586 01:36:13,812 --> 01:36:20,430 1587 01:36:20,430 --> 01:36:25,920 And then what we'll just say here is instead of doing anything here, 1588 01:36:25,920 --> 01:36:32,933 we'll just say customCameraReady true. 1589 01:36:32,933 --> 01:36:35,516 And then what we're going to do is we're just going to stick-- 1590 01:36:35,516 --> 01:36:37,940 why is this [? going there? ?] Oh. 1591 01:36:37,940 --> 01:36:41,890 Forgot to say async here. 1592 01:36:41,890 --> 01:36:46,410 We're going to actually just stick the camera right after these buttons. 1593 01:36:46,410 --> 01:36:51,960 We're just going to say this.state.customCameraReady. 1594 01:36:51,960 --> 01:37:01,860 And we're just going to actually stick in the camera component. 1595 01:37:01,860 --> 01:37:04,620 1596 01:37:04,620 --> 01:37:08,060 And it's just called Expo.camera. 1597 01:37:08,060 --> 01:37:10,040 So we're going to say Expo.camera. 1598 01:37:10,040 --> 01:37:12,980 1599 01:37:12,980 --> 01:37:19,340 Style equals width 400, height 400. 1600 01:37:19,340 --> 01:37:28,680 And type is sort of the camera constant. 1601 01:37:28,680 --> 01:37:30,560 There's back and front. 1602 01:37:30,560 --> 01:37:34,920 So let's pick one of those to start. 1603 01:37:34,920 --> 01:37:38,270 And we'll just say type equals Expo.camera.constants. 1604 01:37:38,270 --> 01:37:42,650 1605 01:37:42,650 --> 01:37:47,765 We'll start with front, and we'll maybe do back later. 1606 01:37:47,765 --> 01:37:50,870 Well, I'll start with back because that's gonna be more normal. 1607 01:37:50,870 --> 01:37:52,950 So that will just be that. 1608 01:37:52,950 --> 01:37:55,840 And so then-- unexpected token. 1609 01:37:55,840 --> 01:37:56,340 Oops. 1610 01:37:56,340 --> 01:37:57,340 I forgot this. 1611 01:37:57,340 --> 01:37:57,840 OK. 1612 01:37:57,840 --> 01:38:01,840 1613 01:38:01,840 --> 01:38:02,840 [INAUDIBLE] 1614 01:38:02,840 --> 01:38:07,840 1615 01:38:07,840 --> 01:38:09,340 OK. 1616 01:38:09,340 --> 01:38:22,380 So now what I'm gonna do is I'm gonna launch the custom 1617 01:38:22,380 --> 01:38:24,792 camera just if component did mount. 1618 01:38:24,792 --> 01:38:26,250 Did I already define that anywhere? 1619 01:38:26,250 --> 01:38:27,610 No. 1620 01:38:27,610 --> 01:38:28,420 OK. 1621 01:38:28,420 --> 01:38:33,570 But I'm gonna say customCameraReady false. 1622 01:38:33,570 --> 01:38:35,495 Component did mount. 1623 01:38:35,495 --> 01:38:38,220 1624 01:38:38,220 --> 01:38:40,140 this.launchCustomCameraAsync. 1625 01:38:40,140 --> 01:38:42,650 1626 01:38:42,650 --> 01:38:43,530 OK. 1627 01:38:43,530 --> 01:38:46,240 So now actually, there's now a camera component 1628 01:38:46,240 --> 01:38:50,080 that's just embedded right in the middle of the app. 1629 01:38:50,080 --> 01:38:53,100 And so I can do whatever I want with it. 1630 01:38:53,100 --> 01:38:56,610 It doesn't do anything right now because it doesn't take pictures. 1631 01:38:56,610 --> 01:39:00,300 None of the UI is built out because it's basically fully customizable. 1632 01:39:00,300 --> 01:39:05,010 And so you're responsible for putting together all the building blocks of it. 1633 01:39:05,010 --> 01:39:08,900 So one thing we can do is we can make it flip back and forth between modes just 1634 01:39:08,900 --> 01:39:09,900 by having you tap on it. 1635 01:39:09,900 --> 01:39:13,860 So we can say camera type. 1636 01:39:13,860 --> 01:39:22,530 And we'll start it off by saying Expo.Camera.Constants back. 1637 01:39:22,530 --> 01:39:27,960 1638 01:39:27,960 --> 01:39:34,140 And then here, let's say this.state.cameraType. 1639 01:39:34,140 --> 01:39:38,680 1640 01:39:38,680 --> 01:39:40,570 So now it's the back camera. 1641 01:39:40,570 --> 01:39:49,280 But then what we can do is we can make this a highlight. 1642 01:39:49,280 --> 01:39:49,780 Why not? 1643 01:39:49,780 --> 01:40:06,440 1644 01:40:06,440 --> 01:40:08,685 So now I'm using this touchable highlight thing 1645 01:40:08,685 --> 01:40:15,450 that we used in the video board so that you can touch the camera now. 1646 01:40:15,450 --> 01:40:19,134 I'm just gonna make sure that works by adding a log statement here. 1647 01:40:19,134 --> 01:40:25,470 1648 01:40:25,470 --> 01:40:31,630 So now when I do this, if I tap the camera, 1649 01:40:31,630 --> 01:40:34,340 I can see tap camera showing up here in the logs. 1650 01:40:34,340 --> 01:40:36,560 So what I'm gonna do here is now instead of that, 1651 01:40:36,560 --> 01:40:58,710 I'm gonna say if this.state.cameraType equals Expo camera constants back, 1652 01:40:58,710 --> 01:41:10,630 this.setState camera type Expo camera constants front. 1653 01:41:10,630 --> 01:41:18,810 Else we'll do the opposite of that and set it to be back. 1654 01:41:18,810 --> 01:41:22,380 So now tapping this should switch between the front-facing and 1655 01:41:22,380 --> 01:41:25,235 back-facing camera. 1656 01:41:25,235 --> 01:41:25,735 Or not. 1657 01:41:25,735 --> 01:41:45,115 1658 01:41:45,115 --> 01:41:45,615 Huh. 1659 01:41:45,615 --> 01:41:52,570 1660 01:41:52,570 --> 01:41:53,070 Oh. 1661 01:41:53,070 --> 01:41:59,996 1662 01:41:59,996 --> 01:42:01,370 I'll move this out into a method. 1663 01:42:01,370 --> 01:42:02,870 That might solve the problem. 1664 01:42:02,870 --> 01:43:12,870 1665 01:43:12,870 --> 01:43:13,370 Hmm. 1666 01:43:13,370 --> 01:43:18,870 1667 01:43:18,870 --> 01:43:21,464 I'm super confused at why this doesn't work. 1668 01:43:21,464 --> 01:43:35,430 1669 01:43:35,430 --> 01:43:36,670 OK, so that's getting called. 1670 01:43:36,670 --> 01:43:48,780 1671 01:43:48,780 --> 01:43:54,420 Camera type starts off as something. 1672 01:43:54,420 --> 01:43:57,745 But now it's somehow undefined. 1673 01:43:57,745 --> 01:43:58,245 Huh. 1674 01:43:58,245 --> 01:44:01,724 1675 01:44:01,724 --> 01:44:02,730 OK. 1676 01:44:02,730 --> 01:44:09,050 Well, this is just some sort of weird React thing that I'm confused about. 1677 01:44:09,050 --> 01:44:12,690 But it actually can happen. 1678 01:44:12,690 --> 01:44:16,280 And I've done this before when I was practicing for this. 1679 01:44:16,280 --> 01:44:17,087 So it does work. 1680 01:44:17,087 --> 01:44:18,920 I'm not sure why it's not working right now. 1681 01:44:18,920 --> 01:44:21,890 1682 01:44:21,890 --> 01:44:22,730 Cool. 1683 01:44:22,730 --> 01:44:30,860 So just to show that the other way camera does actually work, 1684 01:44:30,860 --> 01:44:33,590 I'll just change this default so that it says front. 1685 01:44:33,590 --> 01:44:40,770 And then now, the default here will be instead of the back-facing camera, 1686 01:44:40,770 --> 01:44:48,480 it should be front. 1687 01:44:48,480 --> 01:44:54,216 1688 01:44:54,216 --> 01:44:56,610 Ah. 1689 01:44:56,610 --> 01:44:57,360 Type front. 1690 01:44:57,360 --> 01:44:59,815 1691 01:44:59,815 --> 01:45:00,690 That was the problem. 1692 01:45:00,690 --> 01:45:08,850 1693 01:45:08,850 --> 01:45:14,470 I forgot this type thing. 1694 01:45:14,470 --> 01:45:14,970 OK. 1695 01:45:14,970 --> 01:45:20,120 So now if I tap it, it flips back and forth. 1696 01:45:20,120 --> 01:45:20,620 Cool. 1697 01:45:20,620 --> 01:45:23,910 1698 01:45:23,910 --> 01:45:27,740 I don't know what the lesson is there except read the documentation closely. 1699 01:45:27,740 --> 01:45:36,220 And when it says constants.type.back, don't miss the type part. 1700 01:45:36,220 --> 01:45:37,690 Cool. 1701 01:45:37,690 --> 01:45:44,920 So there's actually a ton of other APIs that Expo has. 1702 01:45:44,920 --> 01:45:49,110 So these include push notifications, calendar, gyroscope, accelerometer, 1703 01:45:49,110 --> 01:45:53,010 pedometer, OpenGL view, which lets you do things like Instagram-like filters 1704 01:45:53,010 --> 01:45:56,520 and 3D-gaming type stuff with things like Phaser and Pixi, 1705 01:45:56,520 --> 01:46:01,680 Facebook login and Google login, ads like AdMob, Facebook, fingerprint 1706 01:46:01,680 --> 01:46:08,882 scanner like Touch ID or on iPhone Xs, Face ID, the Secure Store, SQLite, 1707 01:46:08,882 --> 01:46:10,590 and then analytics and [? sack traces, ?] 1708 01:46:10,590 --> 01:46:13,140 and then a few other things, as well. 1709 01:46:13,140 --> 01:46:16,680 It's all on the docs.expo.io thing, that site 1710 01:46:16,680 --> 01:46:20,130 that I've been going to every time I needed to look something up. 1711 01:46:20,130 --> 01:46:23,260 And so this Expo docs is a pretty good augmentation to the normal React 1712 01:46:23,260 --> 01:46:26,040 Native docs that I'm sure you spend a lot of time looking 1713 01:46:26,040 --> 01:46:28,740 at whenever you're doing development. 1714 01:46:28,740 --> 01:46:35,400 And I'm going to put all the code that I was just showing in this repo-- 1715 01:46:35,400 --> 01:46:39,840 github.com/cchever/harvardguestlecture. 1716 01:46:39,840 --> 01:46:43,930 And hopefully, I'll put that up in the next hour or so. 1717 01:46:43,930 --> 01:46:46,110 And so you can refer to if you want to. 1718 01:46:46,110 --> 01:46:48,010 And thanks so much for coming and listening. 1719 01:46:48,010 --> 01:46:50,260 And I hope this helps you build cool stuff that you 1720 01:46:50,260 --> 01:46:52,110 want to build on your mobile phones. 1721 01:46:52,110 --> 01:46:53,660 Thanks. 1722 01:46:53,660 --> 01:46:55,324