Files
2026-09-21 11:24:22 +02:00

130 lines
3.8 KiB
C#

using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Devices.Sensors;
namespace LMEMappeCatastaliApp.Services;
public sealed class PreciseLocationService : IAsyncDisposable
{
private CancellationTokenSource? trackingCancellation;
public bool IsTracking => trackingCancellation is not null;
public async Task<PermissionStatus> EnsurePermissionAsync()
{
var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (status != PermissionStatus.Granted)
{
status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
}
return status;
}
public async Task<LocationSnapshot?> GetCurrentLocationAsync(CancellationToken cancellationToken = default)
{
var permission = await EnsurePermissionAsync();
if (permission != PermissionStatus.Granted)
{
return null;
}
Location? location = null;
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Best, TimeSpan.FromSeconds(8));
location = await Geolocation.Default.GetLocationAsync(request, cancellationToken);
}
catch (FeatureNotSupportedException)
{
return null;
}
if (location is null)
{
var lastKnown = await Geolocation.Default.GetLastKnownLocationAsync();
if (lastKnown is not null && lastKnown.Timestamp >= DateTimeOffset.UtcNow.AddMinutes(-15))
{
location = lastKnown;
}
}
return location is null ? null : ToSnapshot(location);
}
public async Task StartTrackingAsync(Func<LocationSnapshot, Task> onLocation, Func<string, Task> onError)
{
if (trackingCancellation is not null)
{
return;
}
var permission = await EnsurePermissionAsync();
if (permission != PermissionStatus.Granted)
{
await onError("Permesso GPS non concesso.");
return;
}
trackingCancellation = new CancellationTokenSource();
var token = trackingCancellation.Token;
_ = Task.Run(async () =>
{
while (!token.IsCancellationRequested)
{
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Best, TimeSpan.FromSeconds(5));
var location = await Geolocation.Default.GetLocationAsync(request, token);
if (location is not null)
{
await onLocation(ToSnapshot(location));
}
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
await onError(ex.Message);
await Task.Delay(TimeSpan.FromSeconds(2), token);
}
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
}, token);
}
public void StopTracking()
{
trackingCancellation?.Cancel();
trackingCancellation?.Dispose();
trackingCancellation = null;
}
public ValueTask DisposeAsync()
{
StopTracking();
return ValueTask.CompletedTask;
}
private static LocationSnapshot ToSnapshot(Location location) => new(
location.Latitude,
location.Longitude,
location.Accuracy,
location.Altitude,
location.Course,
location.Speed,
location.Timestamp);
}
public sealed record LocationSnapshot(
double Latitude,
double Longitude,
double? Accuracy,
double? Altitude,
double? Course,
double? Speed,
DateTimeOffset Timestamp);