Files
I150/srcs/RobotNet10/RobotApp/RobotNet10.RobotApp.Client/Pages/Motion/ManualControl.razor
2026-07-03 16:37:12 +07:00

134 lines
4.5 KiB
Plaintext

@page "/motion/manualcontrol"
@rendermode InteractiveWebAssemblyNoPrerender
@implements IAsyncDisposable
@using RobotNet10.RobotApp.Client.Clients
@using RobotNet10.RobotApp.Client.Components.Motion
@using RobotNet10.RobotApp.Client.Shared.Motion
@using Microsoft.AspNetCore.SignalR.Client
@using MudBlazor
<PageTitle>Manual Control</PageTitle>
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="mt-4">
@* Disconnected Overlay *@
<MudOverlay Visible="@(!isHubReady)" DarkBackground="true" ZIndex="9999" AutoClose="false">
<MudStack AlignItems="AlignItems.Center" Spacing="4">
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
<MudText Typo="Typo.h5" Color="Color.Primary">MotionHub Disconnected</MudText>
<MudText Typo="Typo.body1">Waiting for connection...</MudText>
</MudStack>
</MudOverlay>
<MudStack Spacing="4">
@* 4 Cards Grid *@
<MudGrid>
@* Card 1: Manual Control *@
<MudItem xs="12" md="6">
<ManualControlCard HubClient="motionHubClient" IsHubReady="isHubReady" />
</MudItem>
@* Card 2: Odometry (from OdometryService → XLOC) *@
<MudItem xs="12" md="6">
<OdometryCard Odometry="currentOdometry" IsHubReady="odometryHubReady" />
</MudItem>
@* Card 3: Lift Module *@
<MudItem xs="12" md="6">
<LiftModuleCard HubClient="motionHubClient" IsHubReady="isHubReady" />
</MudItem>
@* Card 4: Rotation Module *@
<MudItem xs="12" md="6">
<RotationModuleCard HubClient="motionHubClient" IsHubReady="isHubReady" />
</MudItem>
</MudGrid>
</MudStack>
</MudContainer>
<MudThemeProvider IsDarkMode />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
@code {
[Inject] private MotionHubClient MotionHubClientInjected { get; set; } = null!;
[Inject] private OdometryHubClient OdometryHubClientInjected { get; set; } = null!;
[Inject] private ISnackbar Snackbar { get; set; } = null!;
private MotionHubClient motionHubClient = null!;
private bool isHubReady = false;
private OdometryHubClient odometryHubClient = null!;
private bool odometryHubReady = false;
private OdometryDto? currentOdometry;
protected override async Task OnInitializedAsync()
{
motionHubClient = MotionHubClientInjected;
odometryHubClient = OdometryHubClientInjected;
// Subscribe to connection state changes
motionHubClient.ConnectionStateChanged += OnConnectionStateChanged;
odometryHubClient.ConnectionStateChanged += OnOdometryConnectionStateChanged;
odometryHubClient.OdometryReceived += OnOdometryReceived;
try
{
await motionHubClient.StartAsync();
isHubReady = motionHubClient.IsConnected;
// Wait a bit for connection to establish
await Task.Delay(500);
isHubReady = motionHubClient.IsConnected;
await odometryHubClient.StartAsync();
odometryHubReady = odometryHubClient.IsConnected;
if (odometryHubReady)
{
currentOdometry = await odometryHubClient.GetCurrentOdometryAsync();
}
}
catch (Exception ex)
{
Snackbar.Add($"Error initializing: {ex.Message}", Severity.Error);
isHubReady = false;
}
}
private void OnConnectionStateChanged(HubConnectionState state)
{
isHubReady = state == HubConnectionState.Connected;
InvokeAsync(StateHasChanged);
}
private void OnOdometryConnectionStateChanged(HubConnectionState state)
{
odometryHubReady = state == HubConnectionState.Connected;
InvokeAsync(StateHasChanged);
}
private void OnOdometryReceived(OdometryDto dto)
{
currentOdometry = dto;
InvokeAsync(StateHasChanged);
}
public async ValueTask DisposeAsync()
{
if (motionHubClient != null)
{
motionHubClient.ConnectionStateChanged -= OnConnectionStateChanged;
}
if (odometryHubClient != null)
{
odometryHubClient.ConnectionStateChanged -= OnOdometryConnectionStateChanged;
odometryHubClient.OdometryReceived -= OnOdometryReceived;
}
await ValueTask.CompletedTask;
}
}