iOS LocationService complete.

This commit is contained in:
David Britch 2018-02-20 17:52:19 +00:00
parent 1fa48de667
commit b9835a3e72
10 changed files with 31 additions and 130 deletions

View File

@ -48,12 +48,10 @@ namespace eShopOnContainers
{
await InitNavigation();
}
if (_settingsService.AllowGpsLocation && !_settingsService.UseFakeLocation)
{
await GetGpsLocation();
}
if (!_settingsService.UseMocks && !string.IsNullOrEmpty(_settingsService.AuthAccessToken))
{
await SendCurrentLocation();
@ -74,9 +72,10 @@ namespace eShopOnContainers
if (locator.IsGeolocationEnabled && locator.IsGeolocationAvailable)
{
//locationService.AllowsBackgroundUpdates = true;
locator.DesiredAccuracy = 50;
// Delay getting the position to ensure that the UI has finished updating
await Task.Delay(2000);
var position = await locator.GetPositionAsync();
_settingsService.Latitude = position.Latitude.ToString();

View File

@ -13,16 +13,16 @@ namespace eShopOnContainers.Core.Services.Basket
BuyerId = "9245fe4a-d402-451c-b9ed-9c1a04247482",
Items = new List<BasketItem>
{
new BasketItem { Id = "1", PictureUrl = Device.RuntimePlatform != Device.UWP ? "fake_product_01.png" : "Assets/fake_product_01.png", ProductId = Common.Common.MockCatalogItemId01, ProductName = ".NET Bot Blue Sweatshirt (M)", Quantity = 1, UnitPrice = 19.50M },
new BasketItem { Id = "2", PictureUrl = Device.RuntimePlatform != Device.UWP ? "fake_product_04.png" : "Assets/fake_product_04.png", ProductId = Common.Common.MockCatalogItemId04, ProductName = ".NET Black Cupt", Quantity = 1, UnitPrice = 17.00M }
new BasketItem { Id = "1", PictureUrl = Device.RuntimePlatform != Device.UWP ? "fake_product_01.png" : "Assets/fake_product_01.png", ProductId = Common.Common.MockCatalogItemId01, ProductName = ".NET Bot Blue Sweatshirt (M)", Quantity = 1, UnitPrice = 19.50M },
new BasketItem { Id = "2", PictureUrl = Device.RuntimePlatform != Device.UWP ? "fake_product_04.png" : "Assets/fake_product_04.png", ProductId = Common.Common.MockCatalogItemId04, ProductName = ".NET Black Cupt", Quantity = 1, UnitPrice = 17.00M }
}
};
public async Task<CustomerBasket> GetBasketAsync(string guidUser, string token)
{
await Task.Delay(500);
await Task.Delay(10);
if(string.IsNullOrEmpty(guidUser) || string.IsNullOrEmpty(token))
if (string.IsNullOrEmpty(guidUser) || string.IsNullOrEmpty(token))
{
return new CustomerBasket();
}
@ -32,7 +32,7 @@ namespace eShopOnContainers.Core.Services.Basket
public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket customerBasket, string token)
{
await Task.Delay(500);
await Task.Delay(10);
if (string.IsNullOrEmpty(token))
{
@ -46,7 +46,7 @@ namespace eShopOnContainers.Core.Services.Basket
public async Task ClearBasketAsync(string guidUser, string token)
{
await Task.Delay(500);
await Task.Delay(10);
if (string.IsNullOrEmpty(token))
{

View File

@ -24,40 +24,40 @@ namespace eShopOnContainers.Core.Services.Catalog
private ObservableCollection<CatalogItem> MockCatalog = new ObservableCollection<CatalogItem>
{
new CatalogItem { Id = Common.Common.MockCatalogItemId01, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_01.png" : "Assets/fake_product_01.png", Name = ".NET Bot Blue Sweatshirt (M)", Price = 19.50M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 2, CatalogType = "T-Shirt" },
new CatalogItem { Id = Common.Common.MockCatalogItemId02, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_02.png" : "Assets/fake_product_02.png", Name = ".NET Bot Purple Sweatshirt (M)", Price = 19.50M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 2, CatalogType = "T-Shirt" },
new CatalogItem { Id = Common.Common.MockCatalogItemId03, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_03.png" : "Assets/fake_product_03.png", Name = ".NET Bot Black Sweatshirt (M)", Price = 19.95M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 2, CatalogType = "T-Shirt" },
new CatalogItem { Id = Common.Common.MockCatalogItemId04, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_04.png" : "Assets/fake_product_04.png", Name = ".NET Black Cupt", Price = 17.00M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 1, CatalogType = "Mug" },
new CatalogItem { Id = Common.Common.MockCatalogItemId05, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_05.png" : "Assets/fake_product_05.png", Name = "Azure Black Sweatshirt (M)", Price = 19.50M, CatalogBrandId = 1, CatalogBrand = "Azure", CatalogTypeId = 2, CatalogType = "T-Shirt" }
new CatalogItem { Id = Common.Common.MockCatalogItemId01, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_01.png" : "Assets/fake_product_01.png", Name = ".NET Bot Blue Sweatshirt (M)", Price = 19.50M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 2, CatalogType = "T-Shirt" },
new CatalogItem { Id = Common.Common.MockCatalogItemId02, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_02.png" : "Assets/fake_product_02.png", Name = ".NET Bot Purple Sweatshirt (M)", Price = 19.50M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 2, CatalogType = "T-Shirt" },
new CatalogItem { Id = Common.Common.MockCatalogItemId03, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_03.png" : "Assets/fake_product_03.png", Name = ".NET Bot Black Sweatshirt (M)", Price = 19.95M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 2, CatalogType = "T-Shirt" },
new CatalogItem { Id = Common.Common.MockCatalogItemId04, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_04.png" : "Assets/fake_product_04.png", Name = ".NET Black Cupt", Price = 17.00M, CatalogBrandId = 2, CatalogBrand = "Visual Studio", CatalogTypeId = 1, CatalogType = "Mug" },
new CatalogItem { Id = Common.Common.MockCatalogItemId05, PictureUri = Device.RuntimePlatform != Device.UWP ? "fake_product_05.png" : "Assets/fake_product_05.png", Name = "Azure Black Sweatshirt (M)", Price = 19.50M, CatalogBrandId = 1, CatalogBrand = "Azure", CatalogTypeId = 2, CatalogType = "T-Shirt" }
};
public async Task<ObservableCollection<CatalogItem>> GetCatalogAsync()
{
await Task.Delay(500);
await Task.Delay(10);
return MockCatalog;
}
public async Task<ObservableCollection<CatalogItem>> FilterAsync(int catalogBrandId, int catalogTypeId)
{
await Task.Delay(500);
await Task.Delay(10);
return MockCatalog
.Where(c => c.CatalogBrandId == catalogBrandId &&
c.CatalogTypeId == catalogTypeId)
c.CatalogTypeId == catalogTypeId)
.ToObservableCollection();
}
public async Task<ObservableCollection<CatalogBrand>> GetCatalogBrandAsync()
{
await Task.Delay(500);
await Task.Delay(10);
return MockCatalogBrand;
}
public async Task<ObservableCollection<CatalogType>> GetCatalogTypeAsync()
{
await Task.Delay(500);
await Task.Delay(10);
return MockCatalogType;
}

View File

@ -38,13 +38,13 @@ namespace eShopOnContainers.Core.Services.Marketing
public async Task<ObservableCollection<CampaignItem>> GetAllCampaignsAsync(string token)
{
await Task.Delay(500);
await Task.Delay(10);
return _mockCampaign;
}
public async Task<CampaignItem> GetCampaignByIdAsync(int campaignId, string token)
{
await Task.Delay(500);
await Task.Delay(10);
return _mockCampaign.SingleOrDefault(c => c.Id == campaignId);
}
}

View File

@ -74,7 +74,7 @@ namespace eShopOnContainers.Core.Services.Order
public async Task<ObservableCollection<Models.Orders.Order>> GetOrdersAsync(string token)
{
await Task.Delay(500);
await Task.Delay(10);
if (!string.IsNullOrEmpty(token))
{
@ -88,7 +88,7 @@ namespace eShopOnContainers.Core.Services.Order
public async Task<Models.Orders.Order> GetOrderAsync(int orderId, string token)
{
await Task.Delay(500);
await Task.Delay(10);
if (!string.IsNullOrEmpty(token))
return MockOrders
@ -99,7 +99,7 @@ namespace eShopOnContainers.Core.Services.Order
public async Task CreateOrderAsync(Models.Orders.Order newOrder, string token)
{
await Task.Delay(500);
await Task.Delay(10);
if (!string.IsNullOrEmpty(token))
{

View File

@ -28,7 +28,7 @@ namespace eShopOnContainers.Core.Services.User
public async Task<UserInfo> GetUserInfoAsync(string authToken)
{
await Task.Delay(500);
await Task.Delay(10);
return MockUserInfo;
}
}

View File

@ -160,7 +160,7 @@ namespace eShopOnContainers.Core.ViewModels
{
try
{
await Task.Delay(1000);
await Task.Delay(10);
isAuthenticated = true;
}
@ -189,7 +189,7 @@ namespace eShopOnContainers.Core.ViewModels
{
IsBusy = true;
await Task.Delay(500);
await Task.Delay(10);
LoginUrl = _identityService.CreateAuthorizationRequest();

View File

@ -10,24 +10,19 @@ namespace eShopOnContainers.iOS.Services
{
internal class GeolocationSingleUpdateDelegate : CLLocationManagerDelegate
{
bool _haveHeading;
bool _haveLocation;
readonly Position _position = new Position();
CLHeading _bestHeading;
readonly double _desiredAccuracy;
readonly bool _includeHeading;
readonly TaskCompletionSource<Position> _tcs;
readonly CLLocationManager _manager;
public Task<Position> Task => _tcs?.Task;
public GeolocationSingleUpdateDelegate(CLLocationManager manager, double desiredAccuracy, bool includeHeading, int timeout, CancellationToken cancelToken)
public GeolocationSingleUpdateDelegate(CLLocationManager manager, double desiredAccuracy, int timeout, CancellationToken cancelToken)
{
_manager = manager;
_tcs = new TaskCompletionSource<Position>(manager);
_desiredAccuracy = desiredAccuracy;
_includeHeading = includeHeading;
if (timeout != Timeout.Infinite)
{
@ -76,8 +71,6 @@ namespace eShopOnContainers.iOS.Services
}
}
public override bool ShouldDisplayHeadingCalibration(CLLocationManager manager) => true;
public override void UpdatedLocation(CLLocationManager manager, CLLocation newLocation, CLLocation oldLocation)
{
if (newLocation.HorizontalAccuracy < 0)
@ -97,31 +90,13 @@ namespace eShopOnContainers.iOS.Services
{
_position.Timestamp = new DateTimeOffset((DateTime)newLocation.Timestamp);
}
catch (Exception ex)
catch (Exception)
{
_position.Timestamp = DateTimeOffset.UtcNow;
}
_haveLocation = true;
if ((!_includeHeading || _haveHeading) && _position.Accuracy <= _desiredAccuracy)
{
_tcs.TrySetResult(new Position(_position));
StopListening();
}
}
public override void UpdatedHeading(CLLocationManager manager, CLHeading newHeading)
{
if (newHeading.HeadingAccuracy < 0)
return;
if (_bestHeading != null && newHeading.HeadingAccuracy >= _bestHeading.HeadingAccuracy)
return;
_bestHeading = newHeading;
_position.Heading = newHeading.TrueHeading;
_haveHeading = true;
if (_haveLocation && _position.Accuracy <= _desiredAccuracy)
if (_position.Accuracy <= _desiredAccuracy)
{
_tcs.TrySetResult(new Position(_position));
StopListening();
@ -130,9 +105,6 @@ namespace eShopOnContainers.iOS.Services
private void StopListening()
{
if (CLLocationManager.HeadingAvailable)
_manager.StopUpdatingHeading();
_manager.StopUpdatingLocation();
}
}

View File

@ -15,12 +15,6 @@ namespace eShopOnContainers.iOS.Services
{
public class LocationServiceImplementation : ILocationServiceImplementation
{
bool _deferringUpdates;
readonly CLLocationManager _manager;
Position _lastPosition;
public event EventHandler<PositionErrorEventArgs> PositionError;
public event EventHandler<PositionEventArgs> PositionChanged;
public double DesiredAccuracy { get; set; }
public bool IsGeolocationAvailable => true;
public bool IsGeolocationEnabled
@ -32,21 +26,11 @@ namespace eShopOnContainers.iOS.Services
}
}
public bool SupportsHeading => CLLocationManager.HeadingAvailable;
public LocationServiceImplementation()
{
DesiredAccuracy = 100;
//_manager = GetManager();
//_manager.AuthorizationChanged += OnAuthorizationChanged;
//_manager.Failed += OnFailed;
//_manager.UpdatedLocation += OnUpdatedLocation;
//_manager.UpdatedHeading += OnUpdatedHeading;
//_manager.DeferredUpdatesFinished += OnDeferredUpdatesFinished;
}
void OnDeferredUpdatesFinished(object sender, NSErrorEventArgs e) => _deferringUpdates = false;
#region Internal Implementation
async Task<bool> CheckPermissions(Permission permission)
@ -78,7 +62,7 @@ namespace eShopOnContainers.iOS.Services
#region ILocationServiceImplementation
public async Task<Position> GetPositionAsync(TimeSpan? timeout, CancellationToken? cancelToken = null, bool includeHeading = false)
public async Task<Position> GetPositionAsync(TimeSpan? timeout, CancellationToken? cancelToken = null)
{
var permission = Permission.LocationWhenInUse;
var hasPermission = await CheckPermissions(permission);
@ -96,53 +80,16 @@ namespace eShopOnContainers.iOS.Services
var manager = GetManager();
manager.DesiredAccuracy = DesiredAccuracy;
// Permit background updates if background location mode is enabled
if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0))
{
var backgroundModes = NSBundle.MainBundle.InfoDictionary[(NSString)"UIBackgroundModes"] as NSArray;
manager.AllowsBackgroundLocationUpdates = backgroundModes != null && (backgroundModes.Contains((NSString)"Location") || backgroundModes.Contains((NSString)"location"));
}
// Always prevent location update pausing since we're only listening for a single update
if (UIDevice.CurrentDevice.CheckSystemVersion(6, 0))
manager.PausesLocationUpdatesAutomatically = false;
tcs = new TaskCompletionSource<Position>(manager);
var singleListener = new GeolocationSingleUpdateDelegate(manager, DesiredAccuracy, includeHeading, timeoutMilliseconds, cancelToken.Value);
var singleListener = new GeolocationSingleUpdateDelegate(manager, DesiredAccuracy, timeoutMilliseconds, cancelToken.Value);
manager.Delegate = singleListener;
manager.StartUpdatingLocation();
if (includeHeading && SupportsHeading)
manager.StartUpdatingHeading();
return await singleListener.Task;
//tcs = new TaskCompletionSource<Position>();
//if (_lastPosition == null)
//{
// if (cancelToken != CancellationToken.None)
// cancelToken.Value.Register(() => tcs.TrySetCanceled());
// EventHandler<PositionErrorEventArgs> gotError = null;
// gotError = (s, e) =>
// {
// tcs.TrySetException(new GeolocationException(e.Error));
// PositionError -= gotError;
// };
// PositionError += gotError;
// EventHandler<PositionEventArgs> gotPosition = null;
// gotPosition = (s, e) =>
// {
// tcs.TrySetResult(e.Position);
// PositionChanged += gotPosition;
// };
// PositionChanged += gotPosition;
//}
//else
// tcs.SetResult(_lastPosition);
//return await tcs.Task;
}
#endregion

View File

@ -19,7 +19,6 @@ namespace eShopOnContainers.iOS.Services
return PermissionStatus.Disabled;
var status = CLLocationManager.Status;
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
switch (status)
@ -77,22 +76,6 @@ namespace eShopOnContainers.iOS.Services
locationManager.AuthorizationChanged += authCallback;
var info = NSBundle.MainBundle.InfoDictionary;
//if (permission == Permission.Location)
//{
// if (info.ContainsKey(new NSString("NSLocationAlwaysUsageDescription")))
// locationManager.RequestAlwaysAuthorization();
// else if (info.ContainsKey(new NSString("NSLocationWhenInUseUsageDescription")))
// locationManager.RequestWhenInUseAuthorization();
// else
// throw new UnauthorizedAccessException("On iOS 8.0 and higher you must set either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in your Info.plist file to enable Authorization Requests for Location updates!");
//}
//else if (permission == Permission.LocationAlways)
//{
// if (info.ContainsKey(new NSString("NSLocationAlwaysUsageDescription")))
// locationManager.RequestAlwaysAuthorization();
// else
// throw new UnauthorizedAccessException("On iOS 8.0 and higher you must set either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in your Info.plist file to enable Authorization Requests for Location updates!");
//}
if (permission == Permission.LocationWhenInUse)
{
if (info.ContainsKey(new NSString("NSLocationWhenInUseUsageDescription")))