diff --git a/Components/Pages/Home.razor b/Components/Pages/Home.razor index 2a257f9..e1014ef 100644 --- a/Components/Pages/Home.razor +++ b/Components/Pages/Home.razor @@ -23,7 +23,7 @@ -
+
GPS non attivo Nessuna particella selezionata @@ -133,6 +133,7 @@
+ } else if (ActiveTab == "settings") @@ -471,7 +472,13 @@ 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 Task EnableDrawTools() => JS.InvokeVoidAsync("lmeMap.enableDrawTools").AsTask(); + private async Task EnableDrawTools() + { + await JS.InvokeVoidAsync("lmeMap.enableDrawTools"); + 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(); diff --git a/LMEMappeCatastaliApp.csproj b/LMEMappeCatastaliApp.csproj index 5b3b6cb..afe43a6 100644 --- a/LMEMappeCatastaliApp.csproj +++ b/LMEMappeCatastaliApp.csproj @@ -28,8 +28,8 @@ com.companyname.lmemappecatastaliapp - 0.2.0 - 4 + 0.2.1 + 5 None diff --git a/README.md b/README.md index 18e590a..9fa7f28 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,14 @@ App .NET MAUI Blazor Hybrid per Android, iOS, Mac Catalyst e Windows, pensata pe - Import di file KML, KMZ, GeoJSON e JSON. - Inquadramento e pulizia dei layer importati. - Disegno di marker, linee, poligoni e rettangoli. +- Toolbar di disegno completa di icone, modifica, eliminazione singola e pulizia di tutti i disegni/POI. - POI/progetti salvabili in locale con `localStorage`. - GPS nativo MAUI ad alta precisione con permessi Android/iOS. - Marker posizione, cerchio accuratezza in metri, tracciamento percorso. - Controllo se la posizione GPS cade dentro un poligono importato o disegnato. - Interrogazione WFS ufficiale Agenzia delle Entrate attorno alla posizione GPS per evidenziare la particella catastale corrente quando il servizio restituisce la geometria. - Mappa a tutto schermo con tab Catasto, Progetti e Impostazioni, adattabile agli schermi pieghevoli. +- Ingrandimento oltre lo zoom satellitare nativo senza tessere "Map data not yet available". - Tendine concatenate Regione, Comune, Foglio e Particella. - Catalogo dei Comuni incluso nell'APK e cataloghi regionali OnData scaricati in cache solo quando servono. - Ricerca catastale eseguita dal codice .NET nativo, senza DuckDB WebAssembly nella WebView Android. diff --git a/Services/CadastralCatalogService.cs b/Services/CadastralCatalogService.cs index e56d0f1..d1481af 100644 --- a/Services/CadastralCatalogService.cs +++ b/Services/CadastralCatalogService.cs @@ -128,25 +128,28 @@ public sealed class CadastralCatalogService var parcelValues = new string[count]; var inspireIds = new string[count]; - var longitudes = new long[count]; - var latitudes = new long[count]; + var longitudes = new long?[count]; + var latitudes = new long?[count]; await group.ReadAsync(parcelField, parcelValues, cancellationToken: cancellationToken); await group.ReadAsync(inspireIdField, inspireIds, cancellationToken: cancellationToken); - await group.ReadAsync(longitudeField, longitudes, cancellationToken: cancellationToken); - await group.ReadAsync(latitudeField, latitudes, cancellationToken: cancellationToken); + await group.ReadAsync(longitudeField, longitudes.AsMemory(), cancellationToken: cancellationToken); + await group.ReadAsync(latitudeField, latitudes.AsMemory(), cancellationToken: cancellationToken); foreach (var index in matchingIndexes) { var number = parcelValues[index]; - if (string.IsNullOrWhiteSpace(number) || parcels.ContainsKey(number)) + if (string.IsNullOrWhiteSpace(number) + || parcels.ContainsKey(number) + || !latitudes[index].HasValue + || !longitudes[index].HasValue) { continue; } parcels[number] = new ParcelOption( number, - latitudes[index] / 1_000_000d, - longitudes[index] / 1_000_000d, + latitudes[index]!.Value / 1_000_000d, + longitudes[index]!.Value / 1_000_000d, inspireIds[index] ?? string.Empty); } } diff --git a/wwwroot/css/app.css b/wwwroot/css/app.css index b56f283..79b3b3e 100644 --- a/wwwroot/css/app.css +++ b/wwwroot/css/app.css @@ -152,8 +152,10 @@ input[type="checkbox"] { .gps-overlay { position: absolute; - right: 12px; - bottom: 78px; + top: 72px; + right: auto; + bottom: auto; + left: 12px; z-index: 850; display: grid; grid-template-columns: minmax(160px, auto) auto auto; @@ -164,6 +166,11 @@ input[type="checkbox"] { border-radius: 8px; background: rgba(255, 255, 255, 0.95); box-shadow: 0 3px 14px rgba(0, 0, 0, 0.2); + transition: top 140ms ease; +} + +.gps-overlay.search-open { + top: 140px; } .gps-state { @@ -290,6 +297,13 @@ label { color: var(--ink); } +.danger-command { + width: 100%; + border: 1px solid #cfaca8; + background: #fff; + color: #9b2f26; +} + .file-picker { position: relative; min-height: 52px; @@ -459,13 +473,18 @@ footer { } .gps-overlay { + top: 68px; right: 8px; - bottom: 116px; + bottom: auto; left: 8px; grid-template-columns: minmax(0, 1fr) auto auto; max-width: none; } + .gps-overlay.search-open { + top: 136px; + } + .gps-main, .gps-center { padding: 0 8px; diff --git a/wwwroot/js/lme-map.js b/wwwroot/js/lme-map.js index 782a485..1d8adfa 100644 --- a/wwwroot/js/lme-map.js +++ b/wwwroot/js/lme-map.js @@ -31,6 +31,7 @@ window.lmeMap = { clearImported, addProjectMarker, enableDrawTools, + clearDrawings, saveWorkspace, loadWorkspace, setBaseLayer, @@ -58,11 +59,13 @@ function init() { L.control.zoom({ position: "bottomright" }).addTo(lmeState.map); lmeState.baseLayers.osm = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + maxNativeZoom: 19, maxZoom: 22, attribution: "© OpenStreetMap contributors" }); lmeState.baseLayers.satellite = L.tileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", { + maxNativeZoom: 19, maxZoom: 22, attribution: "Tiles © Esri" }); @@ -288,6 +291,22 @@ function enableDrawTools() { setInfo("Disegno attivo: crea POI, linee e aree sulla mappa."); } +function clearDrawings() { + const count = lmeState.drawings.getLayers().length; + if (!count) { + setInfo("Non ci sono disegni o POI da eliminare."); + return; + } + + if (!window.confirm(`Eliminare ${count} disegni e POI dalla mappa?`)) { + return; + } + + lmeState.drawings.clearLayers(); + updateGpsInsideState(); + setInfo("Disegni e POI eliminati dalla mappa."); +} + function saveWorkspace() { const data = { drawings: lmeState.drawings.toGeoJSON(), diff --git a/wwwroot/lib/leaflet-draw/images/spritesheet-2x.png b/wwwroot/lib/leaflet-draw/images/spritesheet-2x.png new file mode 100644 index 0000000..c45231a Binary files /dev/null and b/wwwroot/lib/leaflet-draw/images/spritesheet-2x.png differ diff --git a/wwwroot/lib/leaflet-draw/images/spritesheet.png b/wwwroot/lib/leaflet-draw/images/spritesheet.png new file mode 100644 index 0000000..97d71c6 Binary files /dev/null and b/wwwroot/lib/leaflet-draw/images/spritesheet.png differ diff --git a/wwwroot/lib/leaflet-draw/images/spritesheet.svg b/wwwroot/lib/leaflet-draw/images/spritesheet.svg new file mode 100644 index 0000000..3c00f30 --- /dev/null +++ b/wwwroot/lib/leaflet-draw/images/spritesheet.svg @@ -0,0 +1,156 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +