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 2 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
8 changes: 8 additions & 0 deletions flutter_google_places_sdk_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.3.0

* BREAKING: Rename `RankPreference` to `TextSearchRankPreference` and introduce `NearbySearchRankPreference`
flikkr marked this conversation as resolved.
Show resolved Hide resolved
* FEAT: Added support for Google Places (new) which can be enabled through `initialize` function.
* FEAT: Added `searchByText` function for Places (new).
* FEAT: Added `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 @@ -48,7 +48,6 @@ linter:
- always_declare_return_types
- always_put_control_body_on_new_line
# - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219
- always_require_non_null_named_parameters
flikkr marked this conversation as resolved.
Show resolved Hide resolved
# - always_specify_types
- annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
Expand Down Expand Up @@ -107,12 +106,10 @@ linter:
- hash_and_equals
- implementation_imports
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
- iterable_contains_unrelated_type
# - join_return_with_assignment # not yet tested
- library_names
- library_prefixes
# - lines_longer_than_80_chars # not yet tested
- list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
# - missing_whitespace_between_adjacent_strings # not yet tested
- no_adjacent_strings_in_list
Expand Down Expand Up @@ -141,7 +138,6 @@ linter:
# - prefer_constructors_over_static_methods # not yet tested
- prefer_contains
# - prefer_double_quotes # opposite of prefer_single_quotes
- prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields
- prefer_final_in_for_each
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ abstract class FlutterGooglePlacesSdkPlatform extends PlatformInterface {

/// "Powered by google" image that should be used when background is white
static const AssetImage ASSET_POWERED_BY_GOOGLE_ON_WHITE = AssetImage(
'assets/google/powered_by_google_on_white.png',
flikkr marked this conversation as resolved.
Show resolved Hide resolved
package: 'flutter_google_places_sdk_platform_interface');
'assets/google/powered_by_google_on_white.png',
package: 'flutter_google_places_sdk_platform_interface',
);

/// "Powered by google" image that should be used when background is not white
static const AssetImage ASSET_POWERED_BY_GOOGLE_ON_NON_WHITE = AssetImage(
'assets/google/powered_by_google_on_non_white.png',
package: 'flutter_google_places_sdk_platform_interface');
'assets/google/powered_by_google_on_non_white.png',
package: 'flutter_google_places_sdk_platform_interface',
);

static final Object _token = Object();

static FlutterGooglePlacesSdkPlatform _instance =
FlutterGooglePlacesSdkMethodChannel();
static FlutterGooglePlacesSdkPlatform _instance = FlutterGooglePlacesSdkMethodChannel();

/// Singleton instance to the platform
static FlutterGooglePlacesSdkPlatform get instance => _instance;
Expand All @@ -40,13 +41,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 +57,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 @@ -85,8 +86,7 @@ abstract class FlutterGooglePlacesSdkPlatform extends PlatformInterface {
LatLngBounds? locationBias,
LatLngBounds? locationRestriction,
}) {
throw UnimplementedError(
'findAutocompletePredictions() has not been implemented.');
throw UnimplementedError('findAutocompletePredictions() has not been implemented.');
}

/// Fetches the details of a place.
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 @@ -9,8 +9,7 @@ const String _CHANNEL_NAME = 'plugins.msh.com/flutter_google_places_sdk';
const MethodChannel _channel = MethodChannel(_CHANNEL_NAME);

/// An implementation of [FlutterGooglePlacesSdkPlatform] that uses method channels.
class FlutterGooglePlacesSdkMethodChannel
extends FlutterGooglePlacesSdkPlatform {
class FlutterGooglePlacesSdkMethodChannel extends FlutterGooglePlacesSdkPlatform {
static const CHANNEL_NAME = _CHANNEL_NAME;

@override
Expand All @@ -19,8 +18,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 +28,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 @@ -102,8 +107,7 @@ class FlutterGooglePlacesSdkMethodChannel
}

FetchPlaceResponse _responseFromPlaceDetails(dynamic value) {
final Place? place =
value == null ? null : Place.fromJson(value.cast<String, dynamic>());
final place = value == null ? null : Place.fromJson(value.cast<String, dynamic>());
return FetchPlaceResponse(place);
}

Expand Down Expand Up @@ -143,4 +147,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
flikkr marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Up @@ -22,3 +22,17 @@ class LatLngBounds with _$LatLngBounds {
factory LatLngBounds.fromJson(Map<String, Object?> json) =>
_$LatLngBoundsFromJson(json);
}

/// An immutable class representing a latitude/longitude aligned circle, with a defined radius.
@Freezed()
class CircularBounds with _$CircularBounds {
flikkr marked this conversation as resolved.
Show resolved Hide resolved
/// 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
Loading