@page "/maps" @rendermode InteractiveWebAssemblyNoPrerender @using MudBlazor @using RobotNet10.RobotApp.Client.Shared.SLAM @using RobotNet10.RobotApp.Client.Clients @using RobotNet10.RobotApp.Client.Components.SLAM @implements IAsyncDisposable @inject SLAMClient CartographerClient @inject ISnackbar Snackbar @inject IDialogService DialogService Map Management Map Management Refresh @if (IsLoading) { } else if (Maps.Count == 0) { No maps found. Create a map by starting scan mapping. } else { Name Created Resolution Size Trajectory Nodes @context.Name @context.CreatedDate.ToString("yyyy-MM-dd HH:mm") @context.Resolution.ToString("F3") m/p @context.Width.ToString("F1") x @context.Height.ToString("F1") m @context.TrajectoryNodeCount } @code { private List Maps { get; set; } = new(); private bool IsLoading { get; set; } = false; protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await CartographerClient.StartAsync(); await RefreshMapsAsync(); } } private async Task RefreshMapsAsync() { if (!CartographerClient.IsConnected) { Snackbar.Add("Not connected to server", Severity.Warning); return; } try { IsLoading = true; StateHasChanged(); Maps = (await CartographerClient.ListMapsAsync()).ToList(); } catch (Exception ex) { Snackbar.Add($"Failed to load maps: {ex.Message}", Severity.Error); } finally { IsLoading = false; StateHasChanged(); } } private async Task LoadMapAsync(string mapName) { try { var success = await CartographerClient.StartLocalizationAsync(mapName); if (success) { Snackbar.Add($"Started localization with map: {mapName}", Severity.Success); } else { Snackbar.Add($"Failed to start localization with map: {mapName}", Severity.Error); } } catch (Exception ex) { Snackbar.Add($"Failed to load map: {ex.Message}", Severity.Error); } } private async Task DeleteMapAsync(string mapName) { var parameters = new DialogParameters { ["MapName"] = mapName }; var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small, FullWidth = true }; var dialog = await DialogService.ShowAsync("Delete Map", parameters, options); var result = await dialog.Result; if (result != null && !result.Canceled) { try { var success = await CartographerClient.DeleteMapAsync(mapName); if (success) { Snackbar.Add($"Map deleted: {mapName}", Severity.Success); await RefreshMapsAsync(); } else { Snackbar.Add($"Failed to delete map: {mapName}", Severity.Error); } } catch (Exception ex) { Snackbar.Add($"Failed to delete map: {ex.Message}", Severity.Error); } } } private string FormatFileSize(long bytes) { string[] sizes = { "B", "KB", "MB", "GB" }; double len = bytes; int order = 0; while (len >= 1024 && order < sizes.Length - 1) { order++; len = len / 1024; } return $"{len:0.##} {sizes[order]}"; } public async ValueTask DisposeAsync() { // CartographerClient is scoped, will be disposed by DI } }