fysoul17 / google_maps_place_picker

Place picker on Google Maps for Flutter
MIT License
223 stars 364 forks source link

Getting the Name of a Place #4

Closed Skquark closed 4 years ago

Skquark commented 4 years ago

I'm enjoying the interface of this addon, I've gone through 4 other Google Place pickers and this one fits my needs better. I got it implemented in my project but ran into an issue getting all the data I was looking for. I can't seem to find the name of the selected place, which I thought would have been built in. I got the address, addressComponents and geo point, and checked all the returned results, but the name's not there. Hoping this is an easy one to put in for the next version.

Another issue I was noticing is after I type a location then select from the list, I see the Select Here button for a moment, but when the keyboard goes away, so does the location that I just picked. I have to press Select Here quickly or it goes back to the spinning. I assume it's not just me and others see this same problem. Otherwise all's good, thanks for the work you put into this, good stuff..

fysoul17 commented 4 years ago

Thanks for reporting.

[Place Name] This is because the geocoding search API is giving limited results, while the auto-complete search gives enough data. (Reference: https://developers.google.com/maps/documentation/geocoding/start) I will have a look if I can fetch additional information using the Place Detail API for camera move search. However, it has to be an optional function, as it will consume 1 more API request for EVERY selection. My primary goal was to use as little API call as possible because place detail costs $17/1000req. If I can add this function, I will let you know.

[Searching issue] It sounds like a new bug. Place result only gets refreshed in 2 ways.

1) when picking from the auto-complete search. 2) dragging the map around and searching based on the pin position.

So, I think 2) is getting performed unnecessarily while searching with the search bar. This will be fixed soon. I will let you know here when this gets fixed.

fysoul17 commented 4 years ago

Please update to Version ^0.5.0 at pubspec.yaml

I added additional results at [PickResult] (Refer to the document). Make sure you set the optional parameter 'usePlaceDetailSearch' to true to get a detailed result from map dragging search as well.

Also, please bear in mind that using 'usePlaceDetailSearch' will charge you 1 additional Place Detail API call per camera moving. You can change debounce time with 'cameraMoveDebounceInMilliseconds' parameter to potentially reduce searching amount OR you can even DISABLE map dragging search by setting 'usePinPointingSearch' to false.

Besides, the bug you reported also has been fixed, and will not perform an unnecessary search.

Skquark commented 4 years ago

That's great, thanks.. Working in my app well. There's one part of the results that I could use a little help with. I'm getting the PickResult with all the meta, but the returned result.photos list returns Photo with the photoReference string instead of the url. This is expected according to the API docs, which according to https://developers.google.com/places/web-service/photos we then take the reference string and make this call: https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=PHOTO_REFERENCE&key=YOUR_API_KEY and it'll returned the desired photoUrl in the size requested. Makes sense, easy enough, wondering if you could add a little utility in there to retrieve that photo.. Wouldn't be surprised if they also charge a point to making the call, but it's a nice bonus still. Hope I'm not asking too much, but having the associated place photos to use would be a nice cherry on top. Thanks.

fysoul17 commented 4 years ago

Interesting feature. However, as the package is made for 'Picking (or searching)' a place and do whatever you want with the data you get from it, the feature you suggest is out of the scope.

The reason I exposed the builder called selectedPlaceWidgetBuilder is for exactly what you want.

You can build a whole new UI/UX with it. Use FloatingCard or your own widget. Your case might be something like:

...
selectedPlaceWidgetBuilder: (_, selectedPlace, state, isSearchBarFocused) {
              return isSearchBarFocused
                  ? Container()
                  // Use FloatingCard or just create your own Widget.
                  : FloatingCard(
                      bottomPosition: <some position>,
                      leftPosition: <some position>,
                      width: <some width>,
                      borderRadius: <border radius if you want rounded frame>,
                      child: state == SearchingState.Searching ? 
                                      Center(child: CircularProgressIndicator()) : 
                                      // The widget which fetches the photo with the result goes here.
                                      // Or use Builder widget.
                                      // In the widget, check if the result is not null, then do whatever you need to do here. You might also need to check if the picked result is same as before and not perform fetching again.
},),
                   );
            },
...

Make sense? Please let me know if you need more information about how to use it or if you are unclear about it.

Skquark commented 4 years ago

Alright, turned out to be simple enough to implement it. I thought it was going to return a url to photo, but after trying it out, it gives the raw image data, so I took that and sorted it out. Here's the functions I wrote up to deal with result.photos.first.photoReference in case you want to integrate it, or someone else reading this could use it...

import 'package:http/http.dart' as http;
import 'package:image/image.dart' as I;
import 'package:path_provider/path_provider.dart';
//....
Future<Image> getPlacePhotoImageFromRef(String ref, {int maxWidth=600}) async {
  http.Response response = await http.get('https://maps.googleapis.com/maps/api/place/photo?maxwidth=$maxWidth&photoreference=$ref&key=$apikey');
  I.Image photo = I.decodeImage(response.bodyBytes);
  return Image.memory(photo.getBytes());
}
Future<File> getPlacePhotoFileFromRef(String ref, {int maxWidth=600}) async {
  http.Response response = await http.get('https://maps.googleapis.com/maps/api/place/photo?maxwidth=$maxWidth&photoreference=$ref&key=$apikey');
  Directory tempDir = await getTemporaryDirectory();
  return File("${tempDir.path}/$ref.jpg").writeAsBytes(response.bodyBytes);
}

That did the trick so I could upload the place photos to filestore from there. Love how easily things snap together with Dart. Thanks again for this piece of the puzzle..

fysoul17 commented 4 years ago

Thanks for sharing such good tips @Skquark .

Also, my apology if I understood incorrectly. It seems you do not need a builder parameter but just a way to retrieve a photo from the result.

Although you already resolved the issue, here is one good package you might need in the future.

I used Google Maps Webserivce in the package to fetch data from APIs. It also has a handy photo fetching API as far as I know. Please have a look if you want to.

Skquark commented 4 years ago

No problem.. I didn't notice the Maps Webservice package when I was looking, that's a handy one to know about. Now I need to add features in my app to use that extra data just because I can. It's a fun learning experience playing with these toy blocks...

fysoul17 commented 4 years ago

Closing as the problem related to the issue is all solved.