1 00:00:02,080 --> 00:00:06,910 For the user location, we got another package built into expo which we can easily use and that's 2 00:00:06,910 --> 00:00:08,740 location package. 3 00:00:08,780 --> 00:00:14,230 Now just as before, you install it by following the instructions here and then you also see a usage example 4 00:00:14,230 --> 00:00:15,520 down there, 5 00:00:15,520 --> 00:00:17,130 so let's quickly do that. 6 00:00:17,140 --> 00:00:24,580 Let's run expo install expo-location in our project and with that installed, we can now also add another 7 00:00:24,570 --> 00:00:27,580 component, besides the image picker component, 8 00:00:27,580 --> 00:00:33,340 I'll add the LocationPicker.js file because that's another thing I want to be able to do in this 9 00:00:33,340 --> 00:00:38,920 app, I want to be able to pick a location. For that in the location picker component, 10 00:00:38,920 --> 00:00:45,490 I'll import React from React of course because it will be a regular React component in the end and import 11 00:00:45,490 --> 00:00:54,040 a couple of things from React Native and amongst these things is the view, a button which allows us to 12 00:00:54,040 --> 00:01:00,610 start getting the user location, some text, also to show a default fallback text while no place has 13 00:01:00,610 --> 00:01:06,640 been selected, an activity indicator to show a spinner whilst we're waiting for the location to be fetched 14 00:01:07,300 --> 00:01:13,840 and maybe also alert to show an alert if something goes wrong and also the stylesheet of course to 15 00:01:13,840 --> 00:01:16,840 style this component. 16 00:01:16,860 --> 00:01:24,390 Now here, I have my location picker component which receives props and then we'll do something, set up 17 00:01:24,390 --> 00:01:33,390 the styles object with Stylesheet.create and in the end, export the location picker component here 18 00:01:33,450 --> 00:01:40,870 as the default, like that. Now for that component, how should its jsx code look like? 19 00:01:40,940 --> 00:01:47,540 Ultimately, that's as always up to you but I will start very simple here and just have a view with a 20 00:01:47,540 --> 00:01:48,460 button in there 21 00:01:49,590 --> 00:01:56,580 which will allow me to start getting the user location and also another view in there which shows for 22 00:01:56,580 --> 00:02:04,080 example my fallback text, no location chosen yet which will later be replaced for a little preview of 23 00:02:04,110 --> 00:02:05,890 the place on a map, 24 00:02:05,910 --> 00:02:10,010 so that's something I'll add later. Now here on the button, I'll therefore say get 25 00:02:13,220 --> 00:02:20,990 user location for example, set the color to Colors.primary and for that as always make sure you 26 00:02:20,990 --> 00:02:27,430 import that colors constant and up on pressing this, I unsurprisingly want to start fetching the 27 00:02:27,430 --> 00:02:28,500 user location. 28 00:02:28,610 --> 00:02:38,180 So here I'll add a new constant, get location handler, which is a function that will then use that location 29 00:02:38,210 --> 00:02:43,760 API we just installed to get the user location and that's what I trigger when I click this button. 30 00:02:45,530 --> 00:02:57,040 Now for the styling here, I'll add a style location picker, on this view here, I'll add another style map 31 00:02:57,190 --> 00:03:03,790 preview, we could also style this text but I'll stick to the default and now add these two styles to 32 00:03:03,790 --> 00:03:15,570 the stylesheet, so location picker here, there I'll add a margin to the bottom of let's say 15 and on 33 00:03:15,570 --> 00:03:27,820 the map preview, there I'll also add a margin to the bottom of let's say 10 and the width of 100% 34 00:03:27,820 --> 00:03:33,380 to take all the available width, a height of maybe 150 35 00:03:33,570 --> 00:03:41,310 and also border color of this grayish color with the #ccc hex code and a border width of one, 36 00:03:41,540 --> 00:03:47,620 it's a little bit like the image preview box. With that, we have this component set up, 37 00:03:47,620 --> 00:03:50,170 we can now include it in the new place screen. 38 00:03:50,200 --> 00:04:00,970 So in that screen component, I'll import location picker from components, location picker like this and add it 39 00:04:00,970 --> 00:04:05,750 in the jsx code below the image picker, just like that. 40 00:04:05,900 --> 00:04:10,540 If we now save that and we have a look, we see this box here. 41 00:04:10,560 --> 00:04:16,110 Now when I click get user location, unsurprisingly the idea is that I start getting the user location. 42 00:04:18,460 --> 00:04:26,110 For that, in our location picker component, we'll need to import some things here - we'll import everything 43 00:04:26,200 --> 00:04:33,610 as location from the expo location package which we just installed. In addition for location, just as 44 00:04:33,610 --> 00:04:40,030 for the camera, we'll have to ask for permissions, so we'll import everything as permissions from expo permissions, 45 00:04:40,060 --> 00:04:47,970 that's also required. With that added here in the get location handler, I have first of all want to check 46 00:04:48,090 --> 00:04:54,540 my permissions and for that, I can copy the approach I use in the image picker. There we have this verify 47 00:04:54,540 --> 00:04:59,010 permissions function which we could of course therefore also outsource and write in a more generic way 48 00:04:59,010 --> 00:05:04,800 to work in different components, here I'll just copy it, verify permissions. Of course here, I'm not asking 49 00:05:04,800 --> 00:05:12,750 for the camera roll but for a location instead and you need to grant location permissions to use this 50 00:05:12,750 --> 00:05:20,820 app and now verify permissions is executed here in the get location handler. We can use async await here 51 00:05:20,850 --> 00:05:28,870 again to await the result of this check, so has permission is what I want to check here and if not, so 52 00:05:29,020 --> 00:05:33,040 if we don't have permissions, well then I'll just return here, 53 00:05:33,040 --> 00:05:39,790 there is no need to continue because we'll not be allowed to fetch the location anyways. Now otherwise 54 00:05:39,970 --> 00:05:47,680 we can continue and now we can use the location package to get the current position async and this 55 00:05:47,680 --> 00:05:53,230 does what the name implies, it gets the current user position. Now locating the user can take a while 56 00:05:53,230 --> 00:05:58,150 which is why this is an asynchronous task and why this returns a promise, a promise which will resolve 57 00:05:58,180 --> 00:06:04,230 once we got the user location or which will be rejected if it fails to fetch one. We can also configure 58 00:06:04,240 --> 00:06:09,400 this with an object you pass to it, again as always in the official docs you learned all about all options 59 00:06:09,400 --> 00:06:16,550 you can set there. For example one option you can set is the timeout and set this to five 60 00:06:16,550 --> 00:06:22,670 seconds to make sure that if we couldn't fetch a location for five seconds, we stop trying 61 00:06:22,670 --> 00:06:23,870 and we throw an error, 62 00:06:23,870 --> 00:06:27,260 so the promise would then be rejected. 63 00:06:27,310 --> 00:06:34,930 Now we can await this and of course wrap it into a try catch block, that's important to make sure we 64 00:06:35,590 --> 00:06:42,610 do handle errors if we fail to fetch a location. Here I will then simply use the alert component which 65 00:06:42,610 --> 00:06:52,410 I'm already importing to throw an alert, could not fetch location and then here, please try again later or pick 66 00:06:52,840 --> 00:06:59,940 a location on the map, which is not possible right now but which we'll soon add and here a button where 67 00:06:59,940 --> 00:07:07,920 we say OK. So that's an alert I show if fetching the location fails for some reason, 68 00:07:08,880 --> 00:07:10,090 otherwise here 69 00:07:10,130 --> 00:07:12,470 I expect to get back a location, 70 00:07:12,500 --> 00:07:15,200 so that's the result of this promise in the end, 71 00:07:15,200 --> 00:07:16,920 a location which we can use. 72 00:07:17,120 --> 00:07:25,720 Now we can then utilize this location with the help of use state to manage some internal state here, 73 00:07:26,830 --> 00:07:36,250 that's the picked location and set picked location and there, we can call use state which has no initial 74 00:07:36,250 --> 00:07:37,810 value here 75 00:07:37,810 --> 00:07:45,550 and then here in the location handler, we can set the picked location 76 00:07:45,600 --> 00:07:52,230 to something, we'll have to see to what for now, to null but before we set anything here, let's 77 00:07:52,290 --> 00:07:57,530 actually console log location to get a feeling for what's inside there. 78 00:07:57,540 --> 00:08:03,740 Now I also want to show a spinner whilst we are fetching, so I'll manage another state in here and that's the 79 00:08:03,740 --> 00:08:10,190 is fetching state and initially, that is of course false 80 00:08:10,220 --> 00:08:12,260 but initially we're not fetching 81 00:08:12,650 --> 00:08:19,670 but then here in the get location handler, before we start getting the location, I'll set is fetching 82 00:08:19,670 --> 00:08:21,090 to true 83 00:08:21,260 --> 00:08:24,410 and once we're done and that also includes if we got an error, 84 00:08:24,410 --> 00:08:31,220 so thereafter I'll set it back to false and now we can use is fetching to show a spinner whilst we are 85 00:08:31,220 --> 00:08:31,640 fetching. 86 00:08:31,640 --> 00:08:39,740 So here if is fetching is true, I'll show the activity indicator and only otherwise, I'll show this text 87 00:08:39,950 --> 00:08:45,920 and later we'll of course not just show the text but we'll also show a map snippet. 88 00:08:45,920 --> 00:08:48,260 Now the activity indicator can be configured, 89 00:08:48,260 --> 00:08:55,440 we can set the size to large and the color to Colors.primary if you want to. With all that, 90 00:08:55,440 --> 00:08:57,940 let's go back and give it a try 91 00:08:57,960 --> 00:09:03,060 here on iOS because whilst I can't add an image here, at least I can check the location and click on 92 00:09:03,060 --> 00:09:07,980 get user location and now I'm asked whether I want to grant permissions which I do want to allow, 93 00:09:08,040 --> 00:09:14,820 always allow and you see that spinner, it's super fast because it's a simulator, it also by the way 94 00:09:14,820 --> 00:09:19,270 simulates the location, it's not the real location of your computer where you're running this on, 95 00:09:19,480 --> 00:09:25,750 instead it's a default dummy location in San Francisco and here on Android, it's the same, if I click 96 00:09:25,780 --> 00:09:33,100 get user location here, I need to grant permissions and once I did that, you see the spinner here and then 97 00:09:33,100 --> 00:09:39,700 you see nothing but in the logs of course, you see something. There you see the objects which were 98 00:09:39,700 --> 00:09:45,670 being logged where you have a coords sub object so to say so a field named coords and the object which 99 00:09:45,670 --> 00:09:53,230 is another object with the accuracy and then a latitude longitude pair that describes this fake location, 100 00:09:53,290 --> 00:10:00,170 both simulators use fake locations. You also got a timestamp. 101 00:10:00,210 --> 00:10:01,700 So now we know what's in there, 102 00:10:01,740 --> 00:10:08,790 so we can set the picked location, we can now set this to let's say an object where you store a latitude 103 00:10:09,540 --> 00:10:17,330 of location.coords.latitude, that's what's in there, right and a longitude, .lng of 104 00:10:17,330 --> 00:10:20,280 location.coords.longitude. 105 00:10:20,320 --> 00:10:26,140 So now we have that picked location available and that picked location can now be used to for example 106 00:10:26,440 --> 00:10:28,440 show a little map snippet here 107 00:10:28,480 --> 00:10:34,420 once we do have a location. Before I do that just one tiny thing, I want to make sure that both the text 108 00:10:34,720 --> 00:10:41,920 and the spinner here is centered, so on the map preview, I'll actually also set justify content to center 109 00:10:42,280 --> 00:10:48,490 and align items to center, so that all the content in there is centered horizontally and vertically, 110 00:10:48,500 --> 00:10:50,310 that's just a tiny thing, 111 00:10:50,320 --> 00:10:52,290 so now you see that all in the center. 112 00:10:52,300 --> 00:10:58,390 But with that, let's now make sure we show a little map snippet that shows the location the user picked.