From ddbed91b10ba54a3b1d84f5227bc5185dcaae253 Mon Sep 17 00:00:00 2001 From: Kirk Charles Niverba Date: Sun, 31 Oct 2021 23:28:41 +0800 Subject: [PATCH] feat: sort autocomplete results --- lib/src/autocomplete_search.dart | 61 +++++++++++++++++++++++++++++--- lib/src/place_picker.dart | 15 +++++++- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/lib/src/autocomplete_search.dart b/lib/src/autocomplete_search.dart index 3bf96d71..86113916 100644 --- a/lib/src/autocomplete_search.dart +++ b/lib/src/autocomplete_search.dart @@ -9,6 +9,7 @@ import 'package:google_maps_place_picker/src/components/rounded_frame.dart'; import 'package:google_maps_place_picker/src/controllers/autocomplete_search_controller.dart'; import 'package:google_maps_webservice/places.dart'; import 'package:provider/provider.dart'; +import 'dart:math'; class AutoCompleteSearch extends StatefulWidget { const AutoCompleteSearch( @@ -32,7 +33,8 @@ class AutoCompleteSearch extends StatefulWidget { this.region, this.initialSearchString, this.searchForInitialValue, - this.autocompleteOnTrailingWhitespace}) + this.autocompleteOnTrailingWhitespace, + this.autocompleteSortByDistance}) : assert(searchBarController != null), super(key: key); @@ -56,6 +58,7 @@ class AutoCompleteSearch extends StatefulWidget { final String? initialSearchString; final bool? searchForInitialValue; final bool? autocompleteOnTrailingWhitespace; + final bool? autocompleteSortByDistance; @override AutoCompleteSearchState createState() => AutoCompleteSearchState(); @@ -257,9 +260,39 @@ class AutoCompleteSearchState extends State { ); } - Widget _buildPredictionOverlay(List predictions) { + Future _buildPredictionOverlay(List predictions) async { + PlaceProvider placeProvider = PlaceProvider.of(context, listen: false); + var map = {}; + var sortedPredictions = []; + + if (placeProvider.currentPosition != null && + widget.autocompleteSortByDistance == true) { + for (var i = 0; i < predictions.length; i++) { + var data = await placeProvider.places.getDetailsByPlaceId( + predictions[i].placeId!, + sessionToken: placeProvider.sessionToken, + ); + + map.addAll({ + predictions[i]: computeDistance( + placeProvider.currentPosition!.latitude, + placeProvider.currentPosition!.longitude, + data.result.geometry!.location.lat, + data.result.geometry!.location.lng, + ) + }); + } + + var sortedMapEntries = map.entries.toList() + ..sort((a, b) => a.value.compareTo(b.value)); + + sortedMapEntries.forEach((element) { + sortedPredictions.add(element.key); + }); + } + return ListBody( - children: predictions + children: (sortedPredictions.isNotEmpty ? sortedPredictions : predictions) .map( (p) => PredictionTile( prediction: p, @@ -297,7 +330,7 @@ class AutoCompleteSearchState extends State { return; } - _displayOverlay(_buildPredictionOverlay(response.predictions)); + _displayOverlay(await _buildPredictionOverlay(response.predictions)); } } @@ -314,4 +347,24 @@ class AutoCompleteSearchState extends State { clearOverlay() { _clearOverlay(); } + + num computeDistance( + num lat1, + num lng1, + num lat2, + num lng2, + ) { + var x = pi / 180; + + lat1 *= x; + lng1 *= x; + lat2 *= x; + lng2 *= x; + + var distance = 2 * + asin(sqrt(pow(sin((lat1 - lat2) / 2), 2) + + cos(lat1) * cos(lat2) * pow(sin((lng1 - lng2) / 2), 2))); + + return distance * 6378137; + } } diff --git a/lib/src/place_picker.dart b/lib/src/place_picker.dart index 7751c310..93a5bea5 100644 --- a/lib/src/place_picker.dart +++ b/lib/src/place_picker.dart @@ -50,6 +50,7 @@ class PlacePicker extends StatefulWidget { this.autocompleteLanguage, this.autocompleteComponents, this.autocompleteTypes, + this.autocompleteSortByDistance = false, this.strictbounds, this.region, this.selectInitialPosition = false, @@ -93,6 +94,16 @@ class PlacePicker extends StatefulWidget { final num? autocompleteRadius; final String? autocompleteLanguage; final List? autocompleteTypes; + + /// If true, the autocomplete will fetch the geolocation details. + /// + /// Be careful in using this because on every autocomplete result, it will query one request to the Google Maps server. + /// + /// If you see no changes with the results, it is possible that it is already sorted. + /// + /// If you have any problems, for example expecting other results or any inquiries: please contact https://github.com/kirkcharlesniv/ + final bool autocompleteSortByDistance; + final List? autocompleteComponents; final bool? strictbounds; final String? region; @@ -306,7 +317,9 @@ class _PlacePickerState extends State { region: widget.region, initialSearchString: widget.initialSearchString, searchForInitialValue: widget.searchForInitialValue, - autocompleteOnTrailingWhitespace: widget.autocompleteOnTrailingWhitespace), + autocompleteOnTrailingWhitespace: + widget.autocompleteOnTrailingWhitespace, + autocompleteSortByDistance: widget.autocompleteSortByDistance), ), SizedBox(width: 5), ],