Fix native map services and add provider selection
This commit is contained in:
1 parent
56211e4b25
commit
3ea51a6842
9 files changed
+1408
-129
No files matched your search
+180
-14
@@ -2,6 +2,8 @@
|
||||
@inject IJSRuntime JS
|
||||
@inject PreciseLocationService LocationService
|
||||
@inject CadastralCatalogService CatalogService
|
||||
@inject OfficialCadastreService OfficialCadastreService
|
||||
@inject LocationSearchService LocationSearchService
|
||||
@implements IAsyncDisposable
|
||||
|
||||
<PageTitle>LME Mappe Catastali</PageTitle>
|
||||
@@ -128,8 +130,10 @@
|
||||
<input @bind="ProjectName" @bind:event="oninput" placeholder="Nome progetto o POI" />
|
||||
</label>
|
||||
<button class="primary-command" @onclick="AddProjectMarker">Aggiungi POI al centro mappa</button>
|
||||
<button class="secondary-command" aria-pressed="@DrawToolsVisible" @onclick="ToggleDrawTools">
|
||||
@(DrawToolsVisible ? "Nascondi strumenti di disegno" : "Mostra strumenti di disegno")
|
||||
</button>
|
||||
<div class="button-row">
|
||||
<button @onclick="EnableDrawTools">Disegna</button>
|
||||
<button @onclick="SaveWorkspace">Salva</button>
|
||||
<button @onclick="LoadWorkspace">Carica</button>
|
||||
</div>
|
||||
@@ -142,11 +146,22 @@
|
||||
<h2>Visualizzazione</h2>
|
||||
<label>
|
||||
Sfondo
|
||||
<select @onchange="ChangeBaseLayer">
|
||||
<option value="satellite">Satellite</option>
|
||||
<option value="osm">Strade</option>
|
||||
<select value="@SelectedBaseLayer" @onchange="ChangeBaseLayer">
|
||||
<option value="satellite">Satellite - Esri World Imagery</option>
|
||||
<option value="osm">Strade - OpenStreetMap</option>
|
||||
<option value="streets-esri">Strade dettagliate - Esri World Street Map</option>
|
||||
<option value="topographic">Topografica - Esri World Topographic</option>
|
||||
<option value="terrain">Terreno - OpenTopoMap</option>
|
||||
<option value="carto">Strade chiare - CARTO Voyager</option>
|
||||
<option value="google-satellite">Satellite - Google Maps</option>
|
||||
<option value="google-roadmap">Strade - Google Maps</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Chiave Google Maps Platform
|
||||
<input type="password" @bind="GoogleMapsApiKey" placeholder="API key" autocomplete="off" />
|
||||
</label>
|
||||
<button class="secondary-command" @onclick="SaveGoogleMapsApiKey">Salva chiave Google</button>
|
||||
<label>
|
||||
Trasparenza catasto
|
||||
<input type="range" min="0" max="1" step="0.05" value="0.75" @onchange="ChangeCadastreOpacity" />
|
||||
@@ -163,7 +178,7 @@
|
||||
|
||||
<h2>GPS e percorso</h2>
|
||||
<label class="toggle-line">
|
||||
<input type="checkbox" checked @onchange="ToggleTrail" />
|
||||
<input type="checkbox" checked="@TrailEnabled" @onchange="ToggleTrail" />
|
||||
Registra la traccia mentre cammini
|
||||
</label>
|
||||
|
||||
@@ -198,6 +213,8 @@
|
||||
private string SearchText { get; set; } = string.Empty;
|
||||
private string ProjectName { get; set; } = string.Empty;
|
||||
private string Status { get; set; } = "online";
|
||||
private string SelectedBaseLayer { get; set; } = "satellite";
|
||||
private string GoogleMapsApiKey { get; set; } = string.Empty;
|
||||
private string SelectedRegionFile { get; set; } = string.Empty;
|
||||
private string SelectedMunicipalityCode { get; set; } = string.Empty;
|
||||
private string SelectedSheet { get; set; } = string.Empty;
|
||||
@@ -206,7 +223,12 @@
|
||||
private double? CatalogFraction { get; set; }
|
||||
private bool CatalogBusy { get; set; }
|
||||
private bool GpsActive { get; set; }
|
||||
private bool DrawToolsVisible { get; set; }
|
||||
private bool TrailEnabled { get; set; }
|
||||
private CancellationTokenSource? CatalogCancellation { get; set; }
|
||||
private CancellationTokenSource? GpsLookupCancellation { get; set; }
|
||||
private long LastGpsLookupAt;
|
||||
private int GpsLookupInProgress;
|
||||
|
||||
private IReadOnlyList<RegionOption> Regions { get; set; } = [];
|
||||
private IReadOnlyList<MunicipalityOption> Municipalities { get; set; } = [];
|
||||
@@ -247,6 +269,15 @@
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
GoogleMapsApiKey = await SecureStorage.Default.GetAsync("google_maps_api_key") ?? string.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
GoogleMapsApiKey = string.Empty;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Regions = await CatalogService.GetRegionsAsync();
|
||||
@@ -274,10 +305,26 @@
|
||||
|
||||
private async Task SearchLocation()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SearchText))
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", "Inserisci una localita, un indirizzo o due coordinate.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.search", SearchText);
|
||||
Status = "ricerca...";
|
||||
var result = await LocationSearchService.SearchAsync(SearchText);
|
||||
if (result is null)
|
||||
{
|
||||
Status = "online";
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", "Localita non trovata. Prova ad aggiungere Comune e Provincia.");
|
||||
return;
|
||||
}
|
||||
|
||||
await JS.InvokeVoidAsync("lmeMap.showSearchResult", result.Latitude, result.Longitude, result.Label);
|
||||
ActiveTab = "map";
|
||||
Status = "online";
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
@@ -322,7 +369,11 @@
|
||||
{
|
||||
Sheets = await CatalogService.GetSheetsAsync(municipality, CreateProgress(), token);
|
||||
CatalogMessage = $"Seleziona uno dei {Sheets.Count} fogli disponibili.";
|
||||
await JS.InvokeVoidAsync("lmeMap.search", $"{municipality.Name}, Italia");
|
||||
var mapLocation = await LocationSearchService.SearchAsync($"{municipality.Name}, Italia", token);
|
||||
if (mapLocation is not null)
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.showSearchResult", mapLocation.Latitude, mapLocation.Longitude, mapLocation.Label);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@@ -392,7 +443,10 @@
|
||||
try
|
||||
{
|
||||
var label = $"{municipality.Name} - foglio {DisplaySheet(SelectedSheet)}, particella {parcel.Number}";
|
||||
await JS.InvokeVoidAsync("lmeMap.locateParcelByPoint", parcel.Latitude, parcel.Longitude, parcel.Number, label);
|
||||
CatalogBusy = true;
|
||||
CatalogMessage = "Scarico il confine dal servizio ufficiale AdE...";
|
||||
var xml = await OfficialCadastreService.GetParcelsNearAsync(parcel.Latitude, parcel.Longitude, 8);
|
||||
await JS.InvokeVoidAsync("lmeMap.displayOfficialParcel", xml, parcel.Latitude, parcel.Longitude, parcel.Number, label, true);
|
||||
ActiveTab = "map";
|
||||
await Task.Delay(30);
|
||||
await JS.InvokeVoidAsync("lmeMap.resize");
|
||||
@@ -402,6 +456,10 @@
|
||||
CatalogMessage = $"Particella non visualizzata: {error.Message}";
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", CatalogMessage);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CatalogBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ToggleGps()
|
||||
@@ -419,11 +477,16 @@
|
||||
private async Task StartGps()
|
||||
{
|
||||
GpsActive = true;
|
||||
GpsLookupCancellation?.Cancel();
|
||||
GpsLookupCancellation?.Dispose();
|
||||
GpsLookupCancellation = new CancellationTokenSource();
|
||||
var lookupToken = GpsLookupCancellation.Token;
|
||||
try
|
||||
{
|
||||
await LocationService.StartTrackingAsync(
|
||||
async location => await InvokeAsync(() => JS.InvokeVoidAsync("lmeMap.setNativeGpsPosition", location)),
|
||||
location => HandleGpsLocationAsync(location, lookupToken),
|
||||
async error => await InvokeAsync(() => JS.InvokeVoidAsync("lmeMap.setGpsError", error)));
|
||||
GpsActive = LocationService.IsTracking;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
@@ -435,10 +498,57 @@
|
||||
private async Task StopGps()
|
||||
{
|
||||
LocationService.StopTracking();
|
||||
GpsLookupCancellation?.Cancel();
|
||||
GpsLookupCancellation?.Dispose();
|
||||
GpsLookupCancellation = null;
|
||||
GpsActive = false;
|
||||
await JS.InvokeVoidAsync("lmeMap.stopGps");
|
||||
}
|
||||
|
||||
private async Task HandleGpsLocationAsync(LocationSnapshot location, CancellationToken cancellationToken)
|
||||
{
|
||||
await InvokeAsync(() => JS.InvokeVoidAsync("lmeMap.setNativeGpsPosition", location));
|
||||
|
||||
var now = Environment.TickCount64;
|
||||
if (now - Interlocked.Read(ref LastGpsLookupAt) < 3_500
|
||||
|| Interlocked.CompareExchange(ref GpsLookupInProgress, 1, 0) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref LastGpsLookupAt, now);
|
||||
try
|
||||
{
|
||||
var radius = Math.Clamp(location.Accuracy ?? 5, 2, 25);
|
||||
var xml = await OfficialCadastreService.GetParcelsNearAsync(
|
||||
location.Latitude,
|
||||
location.Longitude,
|
||||
radius,
|
||||
cancellationToken);
|
||||
await InvokeAsync(() => JS.InvokeVoidAsync(
|
||||
"lmeMap.displayOfficialParcel",
|
||||
xml,
|
||||
location.Latitude,
|
||||
location.Longitude,
|
||||
null,
|
||||
"Posizione GPS",
|
||||
false));
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
await InvokeAsync(() => JS.InvokeVoidAsync(
|
||||
"lmeMap.showInfo",
|
||||
$"Aggiornamento particella GPS non disponibile: {error.GetBaseException().Message}"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Exchange(ref GpsLookupInProgress, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private IProgress<CatalogProgress> CreateProgress() => new Progress<CatalogProgress>(progress =>
|
||||
{
|
||||
_ = InvokeAsync(() =>
|
||||
@@ -472,18 +582,72 @@
|
||||
private Task FitImportedLayers() => JS.InvokeVoidAsync("lmeMap.fitImported").AsTask();
|
||||
private Task ClearImportedLayers() => JS.InvokeVoidAsync("lmeMap.clearImported").AsTask();
|
||||
private Task AddProjectMarker() => JS.InvokeVoidAsync("lmeMap.addProjectMarker", ProjectName).AsTask();
|
||||
private async Task EnableDrawTools()
|
||||
private async Task ToggleDrawTools()
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.enableDrawTools");
|
||||
await SelectTab("map");
|
||||
DrawToolsVisible = !DrawToolsVisible;
|
||||
await JS.InvokeVoidAsync("lmeMap.setDrawToolsVisible", DrawToolsVisible);
|
||||
|
||||
if (DrawToolsVisible)
|
||||
{
|
||||
await SelectTab("map");
|
||||
}
|
||||
}
|
||||
|
||||
private Task ClearDrawings() => JS.InvokeVoidAsync("lmeMap.clearDrawings").AsTask();
|
||||
private Task SaveWorkspace() => JS.InvokeVoidAsync("lmeMap.saveWorkspace").AsTask();
|
||||
private Task LoadWorkspace() => JS.InvokeVoidAsync("lmeMap.loadWorkspace").AsTask();
|
||||
private Task CenterOnGps() => JS.InvokeVoidAsync("lmeMap.centerOnGps").AsTask();
|
||||
private Task ToggleTrail(ChangeEventArgs args) => JS.InvokeVoidAsync("lmeMap.toggleTrail", (bool?)args.Value == true).AsTask();
|
||||
private Task ChangeBaseLayer(ChangeEventArgs args) => JS.InvokeVoidAsync("lmeMap.setBaseLayer", args.Value?.ToString()).AsTask();
|
||||
private async Task ToggleTrail(ChangeEventArgs args)
|
||||
{
|
||||
TrailEnabled = (bool?)args.Value == true;
|
||||
await JS.InvokeVoidAsync("lmeMap.toggleTrail", TrailEnabled);
|
||||
}
|
||||
private async Task ChangeBaseLayer(ChangeEventArgs args)
|
||||
{
|
||||
var requestedLayer = args.Value?.ToString() ?? "satellite";
|
||||
try
|
||||
{
|
||||
if (requestedLayer.StartsWith("google-", StringComparison.Ordinal))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(GoogleMapsApiKey))
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", "Inserisci e salva una chiave Google Maps Platform per usare questo sfondo.");
|
||||
return;
|
||||
}
|
||||
|
||||
await JS.InvokeVoidAsync("lmeMap.configureGoogleMaps", GoogleMapsApiKey.Trim());
|
||||
}
|
||||
|
||||
await JS.InvokeVoidAsync("lmeMap.setBaseLayer", requestedLayer);
|
||||
SelectedBaseLayer = requestedLayer;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", $"Sfondo non disponibile: {error.GetBaseException().Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveGoogleMapsApiKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(GoogleMapsApiKey))
|
||||
{
|
||||
SecureStorage.Default.Remove("google_maps_api_key");
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", "Chiave Google rimossa.");
|
||||
return;
|
||||
}
|
||||
|
||||
GoogleMapsApiKey = GoogleMapsApiKey.Trim();
|
||||
await SecureStorage.Default.SetAsync("google_maps_api_key", GoogleMapsApiKey);
|
||||
await JS.InvokeVoidAsync("lmeMap.configureGoogleMaps", GoogleMapsApiKey);
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", "Chiave Google salvata sul dispositivo.");
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
await JS.InvokeVoidAsync("lmeMap.showInfo", $"Chiave Google non salvata: {error.Message}");
|
||||
}
|
||||
}
|
||||
private Task ChangeCadastreOpacity(ChangeEventArgs args) => JS.InvokeVoidAsync("lmeMap.setCadastreOpacity", args.Value?.ToString()).AsTask();
|
||||
private Task ToggleCadastreLayer(string layer, ChangeEventArgs args) => JS.InvokeVoidAsync("lmeMap.toggleCadastreLayer", layer, (bool?)args.Value == true).AsTask();
|
||||
private Task ExportCadastralImage() => JS.InvokeVoidAsync("lmeMap.exportCadastreView").AsTask();
|
||||
@@ -500,6 +664,8 @@
|
||||
{
|
||||
CancelCatalogWork();
|
||||
LocationService.StopTracking();
|
||||
GpsLookupCancellation?.Cancel();
|
||||
GpsLookupCancellation?.Dispose();
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user