@page "/" @inject IJSRuntime JS @inject PreciseLocationService LocationService @inject CadastralCatalogService CatalogService @implements IAsyncDisposable LME Mappe Catastali
LME Catasto @Status
GPS non attivo Nessuna particella selezionata
@if (ActiveTab is not "map" and not "search") { }
Pronto
@code { private string ActiveTab { get; set; } = "map"; private string SearchText { get; set; } = string.Empty; private string ProjectName { get; set; } = string.Empty; private string Status { get; set; } = "online"; private string SelectedRegionFile { get; set; } = string.Empty; private string SelectedMunicipalityCode { get; set; } = string.Empty; private string SelectedSheet { get; set; } = string.Empty; private string SelectedParcelNumber { get; set; } = string.Empty; private string CatalogMessage { get; set; } = string.Empty; private double? CatalogFraction { get; set; } private bool CatalogBusy { get; set; } private bool GpsActive { get; set; } private CancellationTokenSource? CatalogCancellation { get; set; } private IReadOnlyList Regions { get; set; } = []; private IReadOnlyList Municipalities { get; set; } = []; private IReadOnlyList Sheets { get; set; } = []; private IReadOnlyList Parcels { get; set; } = []; private MunicipalityOption? SelectedMunicipality => Municipalities.FirstOrDefault(item => item.Code == SelectedMunicipalityCode); private ParcelOption? SelectedParcel => Parcels.FirstOrDefault(item => item.Number == SelectedParcelNumber); private string PanelTitle => ActiveTab switch { "cadastre" => "Ricerca catastale", "projects" => "Progetti e dati", "settings" => "Impostazioni", _ => string.Empty }; private string PanelEyebrow => ActiveTab switch { "cadastre" => "Regione, Comune, Foglio, Particella", "projects" => "KML, KMZ, GeoJSON e POI", "settings" => "Mappa, GPS e servizi ufficiali", _ => string.Empty }; private readonly List CadastralLayers = [ new("CP.CadastralParcel", "Particelle", true), new("codice_plla", "Numeri particelle", true), new("CP.CadastralZoning", "Fogli", true), new("fabbricati", "Fabbricati", true), new("strade", "Strade", false), new("acque", "Acque", false) ]; protected override async Task OnInitializedAsync() { try { Regions = await CatalogService.GetRegionsAsync(); } catch (Exception error) { CatalogMessage = $"Catalogo Comuni non disponibile: {error.Message}"; } } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await JS.InvokeVoidAsync("lmeMap.init"); } } private async Task SelectTab(string tab) { ActiveTab = tab; await Task.Delay(30); await JS.InvokeVoidAsync("lmeMap.resize"); } private async Task SearchLocation() { try { await JS.InvokeVoidAsync("lmeMap.search", SearchText); ActiveTab = "map"; } catch (Exception error) { Status = "errore ricerca"; await JS.InvokeVoidAsync("lmeMap.showInfo", $"Ricerca non riuscita: {error.Message}"); } } private async Task OnRegionChanged(ChangeEventArgs args) { CancelCatalogWork(); SelectedRegionFile = args.Value?.ToString() ?? string.Empty; SelectedMunicipalityCode = string.Empty; SelectedSheet = string.Empty; SelectedParcelNumber = string.Empty; Sheets = []; Parcels = []; CatalogMessage = string.Empty; Municipalities = string.IsNullOrWhiteSpace(SelectedRegionFile) ? [] : await CatalogService.GetMunicipalitiesAsync(SelectedRegionFile); } private async Task OnMunicipalityChanged(ChangeEventArgs args) { SelectedMunicipalityCode = args.Value?.ToString() ?? string.Empty; SelectedSheet = string.Empty; SelectedParcelNumber = string.Empty; Sheets = []; Parcels = []; var municipality = SelectedMunicipality; if (municipality is null) { return; } var token = BeginCatalogWork(); CatalogBusy = true; CatalogMessage = "Preparo il catalogo regionale..."; CatalogFraction = null; try { Sheets = await CatalogService.GetSheetsAsync(municipality, CreateProgress(), token); CatalogMessage = $"Seleziona uno dei {Sheets.Count} fogli disponibili."; await JS.InvokeVoidAsync("lmeMap.search", $"{municipality.Name}, Italia"); } catch (OperationCanceledException) { } catch (Exception error) { CatalogMessage = $"Impossibile caricare i fogli: {error.Message}"; await JS.InvokeVoidAsync("lmeMap.showInfo", CatalogMessage); } finally { CatalogBusy = false; CatalogFraction = null; } } private async Task OnSheetChanged(ChangeEventArgs args) { SelectedSheet = args.Value?.ToString() ?? string.Empty; SelectedParcelNumber = string.Empty; Parcels = []; var municipality = SelectedMunicipality; if (municipality is null || string.IsNullOrWhiteSpace(SelectedSheet)) { return; } var token = BeginCatalogWork(); CatalogBusy = true; CatalogMessage = "Carico le particelle del foglio..."; CatalogFraction = null; try { Parcels = await CatalogService.GetParcelsAsync(municipality, SelectedSheet, CreateProgress(), token); CatalogMessage = $"Seleziona una delle {Parcels.Count} particelle disponibili."; } catch (OperationCanceledException) { } catch (Exception error) { CatalogMessage = $"Impossibile caricare le particelle: {error.Message}"; await JS.InvokeVoidAsync("lmeMap.showInfo", CatalogMessage); } finally { CatalogBusy = false; CatalogFraction = null; } } private Task OnParcelChanged(ChangeEventArgs args) { SelectedParcelNumber = args.Value?.ToString() ?? string.Empty; return Task.CompletedTask; } private async Task LocateParcel() { var municipality = SelectedMunicipality; var parcel = SelectedParcel; if (municipality is null || parcel is null) { return; } try { var label = $"{municipality.Name} - foglio {DisplaySheet(SelectedSheet)}, particella {parcel.Number}"; await JS.InvokeVoidAsync("lmeMap.locateParcelByPoint", parcel.Latitude, parcel.Longitude, parcel.Number, label); ActiveTab = "map"; await Task.Delay(30); await JS.InvokeVoidAsync("lmeMap.resize"); } catch (Exception error) { CatalogMessage = $"Particella non visualizzata: {error.Message}"; await JS.InvokeVoidAsync("lmeMap.showInfo", CatalogMessage); } } private async Task ToggleGps() { if (GpsActive) { await StopGps(); } else { await StartGps(); } } private async Task StartGps() { GpsActive = true; try { await LocationService.StartTrackingAsync( async location => await InvokeAsync(() => JS.InvokeVoidAsync("lmeMap.setNativeGpsPosition", location)), async error => await InvokeAsync(() => JS.InvokeVoidAsync("lmeMap.setGpsError", error))); } catch (Exception error) { GpsActive = false; await JS.InvokeVoidAsync("lmeMap.setGpsError", error.Message); } } private async Task StopGps() { LocationService.StopTracking(); GpsActive = false; await JS.InvokeVoidAsync("lmeMap.stopGps"); } private IProgress CreateProgress() => new Progress(progress => { _ = InvokeAsync(() => { CatalogMessage = progress.Message; CatalogFraction = progress.Fraction; StateHasChanged(); }); }); private CancellationToken BeginCatalogWork() { CancelCatalogWork(); CatalogCancellation = new CancellationTokenSource(); return CatalogCancellation.Token; } private void CancelCatalogWork() { CatalogCancellation?.Cancel(); CatalogCancellation?.Dispose(); CatalogCancellation = null; } private static string DisplaySheet(string value) { var trimmed = value.TrimStart('0'); return string.IsNullOrEmpty(trimmed) ? "0" : trimmed; } 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 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 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(); private Task OpenOfficialGeoportal() => Microsoft.Maui.ApplicationModel.Launcher.Default.OpenAsync( new Uri("https://geoportale.cartografia.agenziaentrate.gov.it/")); private Task OpenOfficialReservedArea() => Microsoft.Maui.ApplicationModel.Launcher.Default.OpenAsync( new Uri("https://www.agenziaentrate.gov.it/portale/area-riservata")); private sealed record CadastralLayer(string Key, string Name, bool Enabled); public ValueTask DisposeAsync() { CancelCatalogWork(); LocationService.StopTracking(); return ValueTask.CompletedTask; } }