Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methods and classes for Places (New) API in flutter_google_places_sdk_platform_interface #87

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions flutter_google_places_sdk_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.3.0

* feat: Added support for Google Places (new) which can be enabled through `initialize` function.
* feat: Added `searchByText` and `searchNearby` function for Places (new).
* feat: Added `nameLanguageCode` and `reviews` to Place object.

## 0.2.7

* Now receiving an already converted string list for typesFilter in `findAutocompletePredictions`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ abstract class FlutterGooglePlacesSdkPlatform extends PlatformInterface {
throw UnimplementedError('deinitialize() has not been implemented.');
}

/// Initializes Places for the given application context with the given API key.
/// Initializes Places for the given application context with the given API key. Use [useNewApi] to enable the Places API (New) in the SDK
///
/// All Places API responses are localized using the device's locale.
/// This method should only be called once prior to using the Places API.
/// You may call this method again to update the API key used;
/// if so, all widgets and instances of PlacesClient will now use this new key.
Future<void> initialize(String apiKey, {Locale? locale}) {
Future<void> initialize(String apiKey, {Locale? locale, bool? useNewApi}) {
throw UnimplementedError('initialize() has not been implemented.');
}

Expand All @@ -56,7 +56,7 @@ abstract class FlutterGooglePlacesSdkPlatform extends PlatformInterface {
}

/// Updates the settings of the places client with the given API key and locale.
Future<void> updateSettings(String apiKey, {Locale? locale}) {
Future<void> updateSettings(String apiKey, {Locale? locale, bool? useNewApi}) {
throw UnimplementedError('initialize() has not been implemented.');
}

Expand Down Expand Up @@ -117,4 +117,53 @@ abstract class FlutterGooglePlacesSdkPlatform extends PlatformInterface {
}) {
throw UnimplementedError('fetchPlacePhoto() has not been implemented.');
}

/// Fetches places based on an ambiguous text query.
///
/// Only the requested [fields] will be returned. If none specified,
/// all fields will be returned.
///
/// Note that different fields can incur different billing.
///
/// For more info about billing: https://developers.google.com/maps/documentation/places/android-sdk/usage-and-billing#pricing-new
///
/// For more info on text search: https://developers.google.com/maps/documentation/places/android-sdk/text-search
Future<SearchByTextResponse> searchByText(
String textQuery, {
required List<PlaceField> fields,
String? includedType,
int? maxResultCount,
LatLngBounds? locationBias,
LatLngBounds? locationRestriction,
double? minRating,
bool? openNow,
List<int>? priceLevels,
TextSearchRankPreference? rankPreference,
String? regionCode,
bool? strictTypeFiltering,
}) {
throw UnimplementedError('fetchPlacePhoto() has not been implemented.');
}

/// Search for place(s) of interest using a location.
///
/// Only the requested [fields] will be returned. If none specified,
/// all fields will be returned.
///
/// Note that different fields can incur different billing.
///
/// For more info on nearby search: https://developers.google.com/maps/documentation/places/android-sdk/nearby-search
Future<SearchNearbyResponse> searchNearby({
required List<PlaceField> fields,
required CircularBounds locationRestriction,
List<String>? includedTypes,
List<String>? includedPrimaryTypes,
List<String>? excludedTypes,
List<String>? excludedPrimaryTypes,
NearbySearchRankPreference? rankPreference,
String? regionCode,
int? maxResultCount,
}) {
throw UnimplementedError('searchNearby() has not been implemented.');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class FlutterGooglePlacesSdkMethodChannel
}

@override
Future<void> initialize(String apiKey, {Locale? locale}) {
return _invokeForSettings('initialize', apiKey, locale);
Future<void> initialize(String apiKey, {Locale? locale, bool? useNewApi}) {
return _invokeForSettings('initialize', apiKey, locale, useNewApi);
}

@override
Expand All @@ -29,19 +29,25 @@ class FlutterGooglePlacesSdkMethodChannel
}

@override
Future<void> updateSettings(String apiKey, {Locale? locale}) {
return _invokeForSettings('updateSettings', apiKey, locale);
Future<void> updateSettings(String apiKey, {Locale? locale, bool? useNewApi}) {
return _invokeForSettings('updateSettings', apiKey, locale, useNewApi);
}

Future<void> _invokeForSettings(String methodName, String apiKey, Locale? locale) {
Future<void> _invokeForSettings(
String methodName,
String apiKey,
Locale? locale,
bool? useNewApi,
) {
return _channel.invokeMethod<void>(methodName, {
'apiKey': apiKey,
'useNewApi': useNewApi ?? false,
'locale': locale == null
? null
: {
'country': locale.countryCode,
'language': locale.languageCode,
},
'country': locale.countryCode,
'language': locale.languageCode,
},
});
}

Expand Down Expand Up @@ -143,4 +149,83 @@ class FlutterGooglePlacesSdkMethodChannel
details: 'Response: $value',
);
}

@override
Future<SearchByTextResponse> searchByText(
String textQuery, {
required List<PlaceField> fields,
String? includedType,
int? maxResultCount,
LatLngBounds? locationBias,
LatLngBounds? locationRestriction,
double? minRating,
bool? openNow,
List<int>? priceLevels,
TextSearchRankPreference? rankPreference,
String? regionCode,
bool? strictTypeFiltering,
}) {
if (textQuery.isEmpty) {
throw ArgumentError('Argument query can not be empty');
}
return _channel.invokeListMethod<Map<dynamic, dynamic>>(
'searchByText',
{
'textQuery': textQuery,
'fields': fields.map((e) => e.value).toList(),
'includedType': includedType,
'maxResultCount': maxResultCount,
'locationBias': locationBias?.toJson(),
'locationRestriction': locationRestriction?.toJson(),
'minRating': minRating,
'openNow': openNow,
'priceLevels': priceLevels,
'rankPreference': rankPreference?.value,
'regionCode': regionCode,
'strictTypeFiltering': strictTypeFiltering,
},
).then(_responseFromTextSearch);
}

SearchByTextResponse _responseFromTextSearch(List<Map<dynamic, dynamic>>? value) {
final items =
value?.map((item) => item.cast<String, dynamic>()).map((map) => Place.fromJson(map)).toList(growable: false) ??
[];
return SearchByTextResponse(items);
}

@override
Future<SearchNearbyResponse> searchNearby({
required List<PlaceField> fields,
required CircularBounds locationRestriction,
List<String>? includedTypes,
List<String>? includedPrimaryTypes,
List<String>? excludedTypes,
List<String>? excludedPrimaryTypes,
NearbySearchRankPreference? rankPreference,
String? regionCode,
int? maxResultCount,
}) {
return _channel.invokeListMethod<Map<dynamic, dynamic>>(
'searchNearby',
{
'fields': fields.map((e) => e.value).toList(),
'locationRestriction': locationRestriction.toJson(),
'includedTypes': includedTypes,
'includedPrimaryTypes': includedPrimaryTypes,
'excludedTypes': excludedTypes,
'excludedPrimaryTypes': excludedPrimaryTypes,
'rankPreference': rankPreference?.value,
'regionCode': regionCode,
'maxResultCount': maxResultCount,
},
).then(_responseFromNearbySearch);
}

SearchNearbyResponse _responseFromNearbySearch(List<Map<dynamic, dynamic>>? value) {
final items =
value?.map((item) => item.cast<String, dynamic>()).map((map) => Place.fromJson(map)).toList(growable: false) ??
[];
return SearchNearbyResponse(items);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

import 'package:freezed_annotation/freezed_annotation.dart';

part 'author_attribution.freezed.dart';
part 'author_attribution.g.dart';

@Freezed()
class AuthorAttribution with _$AuthorAttribution {
/// Constructs a [AuthorAttribution] object.
const factory AuthorAttribution({
/// The name of the author.
required String name,

/// The profile photo URI of the author.
required String photoUri,

/// The URI of the author.
required String uri,
}) = _AuthorAttribution;

/// Parse an [AuthorAttribution] from json.
factory AuthorAttribution.fromJson(Map<String, Object?> json) =>
_$AuthorAttributionFromJson(json);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flutter_google_places_sdk_platform_interface/src/types/lat_lng.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'circular_bounds.freezed.dart';
part 'circular_bounds.g.dart';

/// An immutable class representing a latitude/longitude aligned circle, with a defined radius.
@Freezed()
class CircularBounds with _$CircularBounds {
/// constructs a [CircularBounds] object.
const factory CircularBounds({
required LatLng center,
required double radius,
}) = _CircularBounds;

/// Parse an [CircularBounds] from json.
factory CircularBounds.fromJson(Map<String, Object?> json) =>
_$CircularBoundsFromJson(json);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter_google_places_sdk_platform_interface/src/types/opening_h
import 'package:flutter_google_places_sdk_platform_interface/src/types/photo_metadata.dart';
import 'package:flutter_google_places_sdk_platform_interface/src/types/place_type.dart';
import 'package:flutter_google_places_sdk_platform_interface/src/types/plus_code.dart';
import 'package:flutter_google_places_sdk_platform_interface/src/types/review.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'place.freezed.dart';
Expand All @@ -28,6 +29,7 @@ class Place with _$Place {
required List<String>? attributions,
required LatLng? latLng,
required String? name,
required String? nameLanguageCode,
required OpeningHours? openingHours,
required String? phoneNumber,
required List<PhotoMetadata>? photoMetadatas,
Expand All @@ -39,6 +41,7 @@ class Place with _$Place {
required int? utcOffsetMinutes,
required LatLngBounds? viewport,
required Uri? websiteUri,
required List<Review>? reviews,
flikkr marked this conversation as resolved.
Show resolved Hide resolved
}) = _Place;

/// Parse an [Place] from json.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,28 @@ enum PlaceField {
UserRatingsTotal,
@JsonValue('UTC_OFFSET') UTCOffset,
Viewport,
WebsiteUri
;
WebsiteUri,

/// Places (new) API
CurbsidePickup,
CurrentOpeningHours,
Delivery,
DineIn,
EditorialSummary,
IconBackgroundColor,
IconUrl,
Reservable,
Reviews,
SecondaryOpeningHours,
ServesBeer,
ServesBreakfast,
ServesBrunch,
ServesDinner,
ServesLunch,
ServesVegetarianFood,
ServesWine,
Takeout,
WheelchairAccessibleEntrance;

factory PlaceField.fromJson(String name) {
name = name.toLowerCase();
Expand All @@ -39,4 +59,4 @@ enum PlaceField {

extension PlaceFieldValue on PlaceField {
String get value => _$PlaceFieldEnumMap[this]!;
}
}
Loading
Loading