Skip to content

Updates the platform interface for improved extendability. #277

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions geocoding_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 4.0.0

- **BREAKING CHANGES:**
- Releases new interface making the Geocoding plugin easier to extend and
implement on different platforms.
- Moves the old interface into the `legacy` folder. This interface will
remain available but will no longer be maintained. To import the old
interface use `import 'package:geocoding_platform_interface/legacy/geocoding_platform_interface.dart`.

## 3.2.1

- Fixed analysis warnings from `flutter analyse`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export 'src/errors/errors.dart';
export 'src/geocoding_platform_interface.dart';
export 'src/models/models.dart';
export 'src/geocoding.dart';
export 'src/geocoding_platform_factory.dart';
export 'src/types/types.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export 'src/errors/errors.dart';
export 'src/geocoding_platform_interface.dart';
export 'src/models/models.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ abstract class GeocodingPlatform extends PlatformInterface {
///
/// The `localeIdentifier` should be formatted using the syntax:
/// [languageCode]_[countryCode] (eg. en_US or nl_NL).
Future<void> setLocaleIdentifier(
String localeIdentifier,
) {
Future<void> setLocaleIdentifier(String localeIdentifier) {
throw UnimplementedError(
'setLocaleIdentifier() has not been implementated.');
'setLocaleIdentifier() has not been implementated.',
);
}

/// Returns a list of [Location] instances found for the supplied address.
Expand All @@ -51,11 +50,10 @@ abstract class GeocodingPlatform extends PlatformInterface {
/// However in some situations where the supplied address could not be
/// resolved into a single [Location], multiple [Location] instances may be
/// returned.
Future<List<Location>> locationFromAddress(
String address,
) {
Future<List<Location>> locationFromAddress(String address) {
throw UnimplementedError(
'locationFromAddress() has not been implementated.');
'locationFromAddress() has not been implementated.',
);
}

/// Returns true if there is a geocoder implementation present that may return results.
Expand All @@ -80,7 +78,8 @@ abstract class GeocodingPlatform extends PlatformInterface {
double longitude,
) {
throw UnimplementedError(
'placemarkFromCoordinates() has not been implementated.');
'placemarkFromCoordinates() has not been implementated.',
);
}

/// Returns a list of [Placemark] instances found for the supplied address.
Expand All @@ -89,10 +88,9 @@ abstract class GeocodingPlatform extends PlatformInterface {
/// However in some situations where the supplied address could not be
/// resolved into a single [Placemark], multiple [Placemark] instances may be
/// returned.
Future<List<Placemark>> placemarkFromAddress(
String address,
) {
Future<List<Placemark>> placemarkFromAddress(String address) {
throw UnimplementedError(
'placemarkFromAddress() has not been implementated.');
'placemarkFromAddress() has not been implementated.',
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,14 @@ class Location {

final Map<dynamic, dynamic> locationMap = message;
final timestamp = DateTime.fromMillisecondsSinceEpoch(
locationMap['timestamp'].toInt(),
isUtc: true);
locationMap['timestamp'].toInt(),
isUtc: true,
);

if (locationMap['latitude'] == null || locationMap['longitude'] == null) {
throw ArgumentError(
'The parameters latitude and longitude should not be null.');
'The parameters latitude and longitude should not be null.',
);
}

return Location._(
Expand All @@ -74,10 +76,10 @@ class Location {
/// Converts the [Location] instance into a [Map] instance that can be
/// serialized to JSON.
Map<String, dynamic> toJson() => {
'latitude': latitude,
'longitude': longitude,
'timestamp': timestamp.millisecondsSinceEpoch,
};
'latitude': latitude,
'longitude': longitude,
'timestamp': timestamp.millisecondsSinceEpoch,
};

@override
String toString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,18 @@ class Placemark {
/// Converts the [Placemark] instance into a [Map] instance that can be
/// serialized to JSON.
Map<String, dynamic> toJson() => {
'name': name,
'street': street,
'isoCountryCode': isoCountryCode,
'country': country,
'postalCode': postalCode,
'administrativeArea': administrativeArea,
'subAdministrativeArea': subAdministrativeArea,
'locality': locality,
'subLocality': subLocality,
'thoroughfare': thoroughfare,
'subThoroughfare': subThoroughfare,
};
'name': name,
'street': street,
'isoCountryCode': isoCountryCode,
'country': country,
'postalCode': postalCode,
'administrativeArea': administrativeArea,
'subAdministrativeArea': subAdministrativeArea,
'locality': locality,
'subLocality': subLocality,
'thoroughfare': thoroughfare,
'subThoroughfare': subThoroughfare,
};

@override
String toString() {
Expand Down
97 changes: 97 additions & 0 deletions geocoding_platform_interface/lib/src/geocoding.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import 'package:flutter/widgets.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

import 'geocoding_platform_factory.dart';
import 'types/types.dart';

/// Interface for a platform implementation of a [Geocoding] instance.
///
/// Platform implementations should extend this class rather than implement it
/// as `geocoding` package does not consider newly added methods to be breaking
/// changes. Extending this class (using `extends`) ensures that the subclass
/// will get the default implementation, while platform implementations that
/// `implements` this interface will be broken by newly added
/// [Geocoding] methods.
abstract class Geocoding extends PlatformInterface {
/// Creates a new [PlatformWebViewController]
factory Geocoding(GeocodingCreationParams params) {
assert(
GeocodingPlatformFactory.instance != null,
'A platform implementation for `geocoding` has not been set. Please '
'ensure that an implementation of `GeocodingPlatformFactory` has been '
'set te `GeocodingPlatformFactory.instance` before use. For unit '
'testing, `GeocodingPlatformFactory.instance` can be set with your own '
'test implementation.',
);
final Geocoding geocoding = GeocodingPlatformFactory.instance!
.createGeocoding(params);
PlatformInterface.verify(geocoding, _token);
return geocoding;
}

/// Used by the platform implementation to create a new [Geocoding].
///
/// Should only be used by platform implementations because they can't extend
/// a class that only contains a factory constructor.
@protected
Geocoding.implementation(this.params) : super(token: _token);

static final Object _token = Object();

/// The parameters used to initialize the [Geocoding] instance.
final GeocodingCreationParams params;

/// Returns a list of [Location] instances found for the supplied address.
///
/// In most situations the returned list should only contain one entry.
/// However in some situations where the supplied address could not be
/// resolved into a single [Location], multiple [Location] instances may be
/// returned.
Future<List<Location>> locationFromAddress(String address, {Locale? locale}) {
throw UnimplementedError(
'locationFromAddress() has not been implementated.',
);
}

/// Returns true if there is a geocoder implementation present that may return results.
/// If true, there is still no guarantee that any individual geocoding attempt will succeed.
///
///
/// This method is only implemented on Android, calling this on iOS always
/// returns [true].
Future<bool> isPresent() {
throw UnimplementedError('isPresent() has not been implementated.');
}

/// Returns a list of [Placemark] instances found for the supplied
/// coordinates.
///
/// In most situations the returned list should only contain one entry.
/// However in some situations where the supplied coordinates could not be
/// resolved into a single [Placemark], multiple [Placemark] instances may be
/// returned.
Future<List<Placemark>> placemarkFromCoordinates(
double latitude,
double longitude, {
Locale? locale,
}) {
throw UnimplementedError(
'placemarkFromCoordinates() has not been implementated.',
);
}

/// Returns a list of [Placemark] instances found for the supplied address.
///
/// In most situations the returned list should only contain one entry.
/// However in some situations where the supplied address could not be
/// resolved into a single [Placemark], multiple [Placemark] instances may be
/// returned.
Future<List<Placemark>> placemarkFromAddress(
String address, {
Locale? locale,
}) {
throw UnimplementedError(
'placemarkFromAddress() has not been implementated.',
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

import 'geocoding.dart';
import 'types/types.dart';

/// Interface for a platform specific implementation of the geocoding features.
abstract class GeocodingPlatformFactory extends PlatformInterface {
/// Creates a new [GeocodingPlatformFactory].
GeocodingPlatformFactory() : super(token: _token);

static final Object _token = Object();

static GeocodingPlatformFactory? _instance;

/// The instance of [GeocodingPlatformFactory] to use.
///
/// This should return a platform specific instance, which can be used to
/// access geocoding features for that platform.
static GeocodingPlatformFactory? get instance => _instance;

/// Platform-specific plugins should set this with their own platform-specific
/// class that extends [GeocodingPlatformFactory] when they register
/// themselves.
static set instance(GeocodingPlatformFactory? instance) {
if (instance == null) {
throw AssertionError(
'Platform interface can only be set to a non-null instance',
);
}

PlatformInterface.verify(instance, _token);
_instance = instance;
}

/// Creates a new [Geocoding].
///
/// This function should only be called by the app-facing package.
/// Look at using [Geocoding] in `geocoding` package instead.
Geocoding createGeocoding(GeocodingCreationParams params) {
throw UnimplementedError(
'createGeocoding is not implemented on the current platform.',
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:meta/meta.dart';

/// Object specifying creation parameters for creating a [Geocoding].
///
/// Platform specific implementations can add additional fields by extending
/// this class.
///
/// This example demonstrates how to extend the [GeocodingCreationParams] to
/// provide additional platform specific parameters.
///
/// When extending [GeocodingCreationParams] additional
/// parameters should always accept `null` or have a default value to prevent
/// breaking changes.
///
/// ```dart
/// class AndroidGeocodingCreationParams extends GeocodingCreationParams {
/// AndroidGeocodingCreationParams._(
/// // This parameter prevents breaking changes later.
/// // ignore: avoid_unused_constructor_parameters
/// GeocodingCreationParams params, {
/// this.filter,
/// }) : super();
///
/// factory AndroidGeocodingCreationParams.fromGeocodingCreationParams(
/// GeocodingCreationParams params, {
/// String? filter,
/// }) {
/// return AndroidGeocodingCreationParams._(params, filter: filter);
/// }
///
/// final String? filter;
/// }
/// ```
@immutable
class GeocodingCreationParams {
/// Used by the platform implementation to create a new
/// [GeocodingCreationParams].
const GeocodingCreationParams();
}
35 changes: 35 additions & 0 deletions geocoding_platform_interface/lib/src/types/location.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:meta/meta.dart';

/// Describes a location on earth represented by geographical coordinates.the
///
/// Platform specific implementations can add additional fields by extending
/// this class.
@immutable
class Location {
/// Creates a [Location].
const Location({
required this.latitude,
required this.longitude,
required this.timestamp,
});

/// The latitude associated with the placemark.
final double latitude;

/// The longitude associated with the placemark.
final double longitude;

/// The UTC timestamp the coordinates have been requested.
final DateTime timestamp;

@override
bool operator ==(Object other) =>
other is Location &&
other.latitude == latitude &&
other.longitude == longitude &&
other.timestamp == timestamp;

@override
int get hashCode =>
latitude.hashCode ^ longitude.hashCode ^ timestamp.hashCode;
}
Loading