From 6fc8543e22002a689f3255214419f32de9bcb302 Mon Sep 17 00:00:00 2001
From: Rodney Littles II <6969701+RLittlesII@users.noreply.github.com>
Date: Sat, 6 Jan 2024 17:10:18 -0600
Subject: [PATCH] feature: add GpsLocation (#241)
* feature: add GpsLocation
switch Location Events to use GpsLocation for underlying platform locations
add GeoCoordinate
remove beacon events and properties
+semver: minor
* feature: i can read error messages!
---
src/Apple/LocationEventExtensions.cs | 51 +++--------
src/Apple/Locations/CoreLocationManager.cs | 21 -----
src/Core/Geofence/GeoRegion.cs | 19 +++-
src/Core/Locations/Events/ErrorEvent.cs | 6 ++
.../Locations/Events/LocationUpdatedEvent.cs | 6 +-
.../Locations/Events/LocationsUpdatedEvent.cs | 4 +-
.../RegionBeaconsConstraintFailedEvent.cs | 9 --
.../RegionBeaconsConstraintRangedEvent.cs | 9 --
.../Events/RegionBeaconsFailedEvent.cs | 9 --
.../Locations/Events/RegionChangedEvent.cs | 2 +-
src/Core/Locations/Events/VisitedEvent.cs | 6 +-
src/Core/Locations/GeoCoordinate.cs | 58 ++++++++++++
src/Core/Locations/GpsLocation.cs | 91 +++++++++++++++++++
src/Core/Locations/ICoreLocationService.cs | 10 --
src/Core/Locations/IGpsLocation.cs | 50 ++++++++++
15 files changed, 245 insertions(+), 106 deletions(-)
delete mode 100644 src/Core/Locations/Events/RegionBeaconsConstraintFailedEvent.cs
delete mode 100644 src/Core/Locations/Events/RegionBeaconsConstraintRangedEvent.cs
delete mode 100644 src/Core/Locations/Events/RegionBeaconsFailedEvent.cs
create mode 100644 src/Core/Locations/GeoCoordinate.cs
create mode 100644 src/Core/Locations/GpsLocation.cs
create mode 100644 src/Core/Locations/IGpsLocation.cs
diff --git a/src/Apple/LocationEventExtensions.cs b/src/Apple/LocationEventExtensions.cs
index c1075d0c9..a608fe5e0 100644
--- a/src/Apple/LocationEventExtensions.cs
+++ b/src/Apple/LocationEventExtensions.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reactive;
using CoreLocation;
using Foundation;
@@ -35,22 +34,6 @@ internal static class LocationEventExtensions
public static AuthorizationChangedEvent ToNotification(this CLAuthorizationChangedEventArgs args) =>
new(AuthorizationStatuses[args.Status]);
- ///
- /// Converts the to an instance of .
- ///
- /// The arguments.
- /// The changed notification.
- public static RegionBeaconsConstraintFailedEvent ToNotification(this CLRegionBeaconsConstraintFailedEventArgs args) =>
- new();
-
- ///
- /// Converts the to an instance of .
- ///
- /// The arguments.
- /// The changed notification.
- public static RegionBeaconsConstraintRangedEvent ToNotification(this CLRegionBeaconsConstraintRangedEventArgs args) =>
- new();
-
///
/// Converts the to an instance of .
///
@@ -65,7 +48,7 @@ public static HeadingUpdatedEvent ToNotification(this CLHeadingUpdatedEventArgs
/// The arguments.
/// The notification.
public static LocationsUpdatedEvent ToNotification(this CLLocationsUpdatedEventArgs args) =>
- new(args.Locations.Select(x => new GeoLocation(x.Coordinate.Latitude, x.Coordinate.Longitude)));
+ new(args.Locations.Select(location => location.ToGpsLocation()));
///
/// Converts the to .
@@ -74,8 +57,8 @@ public static LocationsUpdatedEvent ToNotification(this CLLocationsUpdatedEventA
/// The notification.
public static LocationUpdatedEvent ToNotification(this CLLocationUpdatedEventArgs args) =>
new(
- args.OldLocation.Coordinate.ToLocation(),
- args.NewLocation.Coordinate.ToLocation());
+ args.OldLocation.ToGpsLocation(),
+ args.NewLocation.ToGpsLocation());
///
/// Converts the to .
@@ -99,7 +82,7 @@ public static RegionChangedEvent ToNotification(this CLRegionStateDeterminedEven
/// The arguments.
/// The notification.
public static ErrorEvent ToNotification(this NSErrorEventArgs args) =>
- new() { };
+ new(new Exception(args.ToString()));
///
/// Converts the to .
@@ -117,34 +100,26 @@ public static VisitedEvent ToNotification(this CLVisitedEventArgs args) =>
public static RegionErrorEvent ToNotification(this CLRegionErrorEventArgs args) =>
new(/*args.Error*/new Exception(), ToGeoRegion(args.Region));
- ///
- /// Converts the to .
- ///
- /// The object.
- /// The notification.
- public static Unit ToNotification(this object obj) => Unit.Default;
-
///
/// Converts a to a .
///
/// The region.
/// The converted value.
- public static GeoRegion ToGeoRegion(this CLRegion region) =>
- new()
- {
- Identifier = region.Identifier,
- Center = region.Center.ToLocation(),
- Radius = region.Radius,
- NotifyOnEntry = region.NotifyOnEntry,
- NotifyOnExit = region.NotifyOnExit
- };
+ public static GeoRegion ToGeoRegion(this CLRegion region) => new(
+ region.Identifier,
+ region.Center.ToLocation(),
+ region.Radius,
+ region.NotifyOnEntry,
+ region.NotifyOnExit);
///
/// Converts the to a .
///
/// The location.
/// The converted vale.
- public static GeoLocation ToLocation(this CLLocationCoordinate2D location) => new(location.Latitude, location.Longitude);
+ public static GeoCoordinate ToLocation(this CLLocationCoordinate2D location) => new(location.Latitude, location.Longitude);
+
+ public static IGpsLocation ToGpsLocation(this CLLocation location) => new GpsLocation(location.Coordinate.Latitude, location.Coordinate.Longitude, location.Altitude, location.Course, location.CourseAccuracy, location.Speed, location.SpeedAccuracy, 0, location.Timestamp.ToLocalTime());
public static DateTime ToLocalTime(this NSDate nsDate)
{
diff --git a/src/Apple/Locations/CoreLocationManager.cs b/src/Apple/Locations/CoreLocationManager.cs
index 9b1fc20c0..5cee3863d 100644
--- a/src/Apple/Locations/CoreLocationManager.cs
+++ b/src/Apple/Locations/CoreLocationManager.cs
@@ -39,21 +39,6 @@ public CoreLocationManager()
handler => _locationManager.Value.DidDetermineState -= handler)
.Select(LocationEventExtensions.ToNotification);
- FailedRangingBeacons =
- Observable
- .FromEvent,
- CLRegionBeaconsConstraintFailedEventArgs>(
- handler => _locationManager.Value.DidFailRangingBeacons += handler,
- handler => _locationManager.Value.DidFailRangingBeacons -= handler)
- .Select(LocationEventExtensions.ToNotification);
-
- RangedBeaconsSatisfyingConstraint =
- Observable
- .FromEvent, CLRegionBeaconsConstraintRangedEventArgs>(
- handler => _locationManager.Value.DidRangeBeaconsSatisfyingConstraint += handler,
- handler => _locationManager.Value.DidRangeBeaconsSatisfyingConstraint -= handler)
- .Select(LocationEventExtensions.ToNotification);
-
StartedMonitoringForRegion =
Observable
.FromEvent, CLRegionEventArgs>(
@@ -138,12 +123,6 @@ public CoreLocationManager()
///
public IObservable DeterminedState { get; }
- ///
- public IObservable FailedRangingBeacons { get; }
-
- ///
- public IObservable RangedBeaconsSatisfyingConstraint { get; }
-
///
public IObservable StartedMonitoringForRegion { get; }
diff --git a/src/Core/Geofence/GeoRegion.cs b/src/Core/Geofence/GeoRegion.cs
index 4fd0ffae5..d8a50b2d7 100644
--- a/src/Core/Geofence/GeoRegion.cs
+++ b/src/Core/Geofence/GeoRegion.cs
@@ -5,6 +5,23 @@ namespace Rocket.Surgery.Airframe
///
public class GeoRegion
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The unique identifier.
+ /// The center point of the region.
+ /// The radius.
+ /// A value indicating whether to notify on entry.
+ /// A value indicating whether to notify on exit.
+ public GeoRegion(string identifier, GeoCoordinate center, double radius, bool notifyOnEntry, bool notifyOnExit)
+ {
+ Identifier = identifier;
+ Center = center;
+ NotifyOnEntry = notifyOnEntry;
+ NotifyOnExit = notifyOnExit;
+ Radius = radius;
+ }
+
///
/// Gets or sets the region identifier.
///
@@ -13,7 +30,7 @@ public class GeoRegion
///
/// Gets or sets the center.
///
- public GeoLocation Center { get; set; }
+ public GeoCoordinate Center { get; set; }
///
/// Gets or sets a value indicating whether to notify on entry of the region.
diff --git a/src/Core/Locations/Events/ErrorEvent.cs b/src/Core/Locations/Events/ErrorEvent.cs
index 53fd66566..bcb261ebf 100644
--- a/src/Core/Locations/Events/ErrorEvent.cs
+++ b/src/Core/Locations/Events/ErrorEvent.cs
@@ -7,6 +7,12 @@ namespace Rocket.Surgery.Airframe
///
public class ErrorEvent
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exception.
+ public ErrorEvent(Exception exception) => Exception = exception;
+
///
/// Gets an exception.
///
diff --git a/src/Core/Locations/Events/LocationUpdatedEvent.cs b/src/Core/Locations/Events/LocationUpdatedEvent.cs
index ea2172f98..e7157155a 100644
--- a/src/Core/Locations/Events/LocationUpdatedEvent.cs
+++ b/src/Core/Locations/Events/LocationUpdatedEvent.cs
@@ -10,7 +10,7 @@ public class LocationUpdatedEvent
///
/// The previous.
/// The current.
- public LocationUpdatedEvent(GeoLocation previous, GeoLocation current)
+ public LocationUpdatedEvent(IGpsLocation? previous, IGpsLocation current)
{
Previous = previous;
Current = current;
@@ -19,11 +19,11 @@ public LocationUpdatedEvent(GeoLocation previous, GeoLocation current)
///
/// Gets the previous location.
///
- public GeoLocation Previous { get; }
+ public IGpsLocation? Previous { get; }
///
/// Gets the current location.
///
- public GeoLocation Current { get; }
+ public IGpsLocation Current { get; }
}
}
\ No newline at end of file
diff --git a/src/Core/Locations/Events/LocationsUpdatedEvent.cs b/src/Core/Locations/Events/LocationsUpdatedEvent.cs
index f88a2637c..a741e7cf3 100644
--- a/src/Core/Locations/Events/LocationsUpdatedEvent.cs
+++ b/src/Core/Locations/Events/LocationsUpdatedEvent.cs
@@ -11,11 +11,11 @@ public class LocationsUpdatedEvent
/// Initializes a new instance of the class.
///
/// The locations.
- public LocationsUpdatedEvent(IEnumerable locations) => Locations = locations;
+ public LocationsUpdatedEvent(IEnumerable locations) => Locations = locations;
///
/// Gets the locations.
///
- public IEnumerable Locations { get; }
+ public IEnumerable Locations { get; }
}
}
\ No newline at end of file
diff --git a/src/Core/Locations/Events/RegionBeaconsConstraintFailedEvent.cs b/src/Core/Locations/Events/RegionBeaconsConstraintFailedEvent.cs
deleted file mode 100644
index c8c6ec20f..000000000
--- a/src/Core/Locations/Events/RegionBeaconsConstraintFailedEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Rocket.Surgery.Airframe
-{
- ///
- /// Represents a beacon constraint failure event.
- ///
- public class RegionBeaconsConstraintFailedEvent
- {
- }
-}
\ No newline at end of file
diff --git a/src/Core/Locations/Events/RegionBeaconsConstraintRangedEvent.cs b/src/Core/Locations/Events/RegionBeaconsConstraintRangedEvent.cs
deleted file mode 100644
index a28fb36ad..000000000
--- a/src/Core/Locations/Events/RegionBeaconsConstraintRangedEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Rocket.Surgery.Airframe
-{
- ///
- /// Represents a beacon constraint event.
- ///
- public class RegionBeaconsConstraintRangedEvent
- {
- }
-}
\ No newline at end of file
diff --git a/src/Core/Locations/Events/RegionBeaconsFailedEvent.cs b/src/Core/Locations/Events/RegionBeaconsFailedEvent.cs
deleted file mode 100644
index 792f960c3..000000000
--- a/src/Core/Locations/Events/RegionBeaconsFailedEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Rocket.Surgery.Airframe
-{
- ///
- /// Represents failed beacon.
- ///
- public class RegionBeaconsFailedEvent
- {
- }
-}
\ No newline at end of file
diff --git a/src/Core/Locations/Events/RegionChangedEvent.cs b/src/Core/Locations/Events/RegionChangedEvent.cs
index 7b54d6237..fffd0a6c1 100644
--- a/src/Core/Locations/Events/RegionChangedEvent.cs
+++ b/src/Core/Locations/Events/RegionChangedEvent.cs
@@ -10,7 +10,7 @@ public class RegionChangedEvent
///
/// The region.
/// The region state.
- public RegionChangedEvent(GeoRegion region, RegionState? state = default)
+ public RegionChangedEvent(GeoRegion region, RegionState? state = RegionState.Unknown)
{
Region = region;
State = state;
diff --git a/src/Core/Locations/Events/VisitedEvent.cs b/src/Core/Locations/Events/VisitedEvent.cs
index 4bf7cc9c4..405373d82 100644
--- a/src/Core/Locations/Events/VisitedEvent.cs
+++ b/src/Core/Locations/Events/VisitedEvent.cs
@@ -14,9 +14,9 @@ public class VisitedEvent
/// The arrival date.
/// The departure date.
/// The accuracy.
- public VisitedEvent(GeoLocation location, DateTimeOffset arrivalDate, DateTimeOffset departureDate, double horizontalAccuracy)
+ public VisitedEvent(GeoCoordinate location, DateTimeOffset arrivalDate, DateTimeOffset departureDate, double horizontalAccuracy)
{
- GeoLocation = location;
+ Location = location;
ArrivalDate = arrivalDate;
DepartureDate = departureDate;
HorizontalAccuracy = horizontalAccuracy;
@@ -30,7 +30,7 @@ public VisitedEvent(GeoLocation location, DateTimeOffset arrivalDate, DateTimeOf
///
/// Gets the geo location.
///
- public GeoLocation GeoLocation { get; }
+ public GeoCoordinate Location { get; }
///
/// Gets the departure date.
diff --git a/src/Core/Locations/GeoCoordinate.cs b/src/Core/Locations/GeoCoordinate.cs
new file mode 100644
index 000000000..d83778f2d
--- /dev/null
+++ b/src/Core/Locations/GeoCoordinate.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace Rocket.Surgery.Airframe
+{
+ ///
+ /// Represents a coordinate.
+ ///
+ /// any of a set of numbers used in specifying the location of a point on a line, on a surface, or in space.
+ public class GeoCoordinate : IEquatable
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The latitude value.
+ /// The longitude value.
+ public GeoCoordinate(double latitude, double longitude)
+ {
+ if (latitude is < -90 or > 90)
+ {
+ throw new ArgumentException($"Invalid latitude value - {latitude}");
+ }
+
+ if (longitude is < -180 or > 180)
+ {
+ throw new ArgumentException($"Invalid longitude value - {longitude}");
+ }
+
+ Latitude = latitude;
+ Longitude = longitude;
+ }
+
+ ///
+ /// Gets the latitude of the coordinate.
+ ///
+ public double Latitude { get; }
+
+ ///
+ /// Gets the longitude of the coordinate.
+ ///
+ public double Longitude { get; }
+
+ public static bool operator ==(GeoCoordinate? left, GeoCoordinate? right) => Equals(left, right);
+
+ public static bool operator !=(GeoCoordinate? left, GeoCoordinate? right) => !Equals(left, right);
+
+ ///
+ public override string ToString() => $"Latitude: {Latitude} - Longitude: {Longitude}";
+
+ ///
+ public bool Equals(GeoCoordinate? other) => other != null && (Latitude, Longitude).Equals((other.Latitude, other.Longitude));
+
+ ///
+ public override bool Equals(object? obj) => obj is GeoCoordinate coordinate && Equals(coordinate);
+
+ ///
+ public override int GetHashCode() => (Latitude, Longitude).GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/src/Core/Locations/GpsLocation.cs b/src/Core/Locations/GpsLocation.cs
new file mode 100644
index 000000000..c37e4edb9
--- /dev/null
+++ b/src/Core/Locations/GpsLocation.cs
@@ -0,0 +1,91 @@
+using System;
+
+namespace Rocket.Surgery.Airframe
+{
+ ///
+ /// Represents a gps location.
+ ///
+ public class GpsLocation : IGpsLocation
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The latitude.
+ /// The longitude.
+ /// The altitude.
+ /// The heading.
+ /// The heading accuracy.
+ /// The speed.
+ /// The speed accuracy.
+ /// The position accuracy.
+ /// The date time of the reading.
+ public GpsLocation(
+ double latitude,
+ double longitude,
+ double altitude,
+ double heading,
+ double headingAccuracy,
+ double speed,
+ double speedAccuracy,
+ double positionAccuracy,
+ DateTimeOffset timestamp)
+ : this(new GeoCoordinate(latitude, longitude), altitude, heading, headingAccuracy, speed, speedAccuracy, positionAccuracy, timestamp)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The position.
+ /// The altitude.
+ /// The heading.
+ /// The heading accuracy.
+ /// The speed.
+ /// The speed accuracy.
+ /// The position accuracy.
+ /// The date time of the reading.
+ public GpsLocation(
+ GeoCoordinate position,
+ double altitude,
+ double heading,
+ double headingAccuracy,
+ double speed,
+ double speedAccuracy,
+ double positionAccuracy,
+ DateTimeOffset timestamp)
+ {
+ Altitude = altitude;
+ Heading = heading;
+ HeadingAccuracy = headingAccuracy;
+ Speed = speed;
+ SpeedAccuracy = speedAccuracy;
+ Position = position;
+ PositionAccuracy = positionAccuracy;
+ Timestamp = timestamp;
+ }
+
+ ///
+ public double Altitude { get; }
+
+ ///
+ public double Heading { get; }
+
+ ///
+ public double HeadingAccuracy { get; }
+
+ ///
+ public double Speed { get; }
+
+ ///
+ public double SpeedAccuracy { get; }
+
+ ///
+ public GeoCoordinate Position { get; }
+
+ ///
+ public double PositionAccuracy { get; }
+
+ ///
+ public DateTimeOffset Timestamp { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Core/Locations/ICoreLocationService.cs b/src/Core/Locations/ICoreLocationService.cs
index 0ec8ec59f..2b4bf57b4 100644
--- a/src/Core/Locations/ICoreLocationService.cs
+++ b/src/Core/Locations/ICoreLocationService.cs
@@ -23,16 +23,6 @@ public interface ICoreLocationService
///
IObservable DeterminedState { get; }
- ///
- /// Gets an observable sequence of region beacon failure notifications.
- ///
- IObservable FailedRangingBeacons { get; }
-
- ///
- /// Gets an observable sequence of beacon range constraint notifications.
- ///
- IObservable RangedBeaconsSatisfyingConstraint { get; }
-
///
/// Gets an observable sequence of regions when the are started being monitored.
///
diff --git a/src/Core/Locations/IGpsLocation.cs b/src/Core/Locations/IGpsLocation.cs
new file mode 100644
index 000000000..7d33879f0
--- /dev/null
+++ b/src/Core/Locations/IGpsLocation.cs
@@ -0,0 +1,50 @@
+using System;
+
+namespace Rocket.Surgery.Airframe
+{
+ ///
+ /// Interface representing a gps location.
+ ///
+ public interface IGpsLocation
+ {
+ ///
+ /// Gets the altitude of the reading.
+ ///
+ double Altitude { get; }
+
+ ///
+ /// Gets the heading of the reading.
+ ///
+ double Heading { get; }
+
+ ///
+ /// Gets the accuracy of the heading.
+ ///
+ double HeadingAccuracy { get; }
+
+ ///
+ /// Gets the current speed.
+ ///
+ double Speed { get; }
+
+ ///
+ /// Gets the accuracy in meters per second for the speed.
+ ///
+ double SpeedAccuracy { get; }
+
+ ///
+ /// Gets the position of the reading.
+ ///
+ GeoCoordinate Position { get; }
+
+ ///
+ /// Gets the position accuracy.
+ ///
+ double PositionAccuracy { get; }
+
+ ///
+ /// Gets the timestamp.
+ ///
+ DateTimeOffset Timestamp { get; }
+ }
+}
\ No newline at end of file