Call StateHasChanged when a new server is discovered so the list updates immediately. Unsubscribe from BeaconClient.OnBeaconResponse in Dispose to prevent callbacks firing after the component is torn down.
173 lines
No EOL
5.2 KiB
Text
173 lines
No EOL
5.2 KiB
Text
@using LANCommander.Launcher.Models
|
|
@using LANCommander.SDK.Models
|
|
@using ListItem = AntDesign.ListItem
|
|
@namespace LANCommander.Launcher.UI
|
|
@implements IDisposable
|
|
@inject IConnectionClient ConnectionClient
|
|
@inject BeaconClient BeaconClient
|
|
@inject NavigationManager NavigationManager
|
|
@inject AuthenticationService AuthenticationService
|
|
@inject LocalizationService LocalizationService
|
|
|
|
<PageHeader>
|
|
<TitleTemplate>
|
|
@LocalizationService.GetString("Connect")
|
|
</TitleTemplate>
|
|
</PageHeader>
|
|
|
|
<Form Model="Model" OnFinish="() => SelectServer(ServerAddress)">
|
|
|
|
@if (OfflineModeAvailable)
|
|
{
|
|
<Alert Message="@LocalizationService.GetString("ServerOfflineMessage")" Type="AlertType.Warning" ShowIcon="true" Style="margin-bottom: 16px;" />
|
|
}
|
|
|
|
<FormItem>
|
|
<Flex Gap="FlexGap.Small">
|
|
<Input @bind-Value="ServerAddress" Placeholder="@LocalizationService.GetString("ServerAddressPlaceholder")" AutoFocus Disabled="Connecting" />
|
|
<Button Type="ButtonType.Primary" HtmlType="submit" Disabled="Connecting" Loading="Connecting">@LocalizationService.GetString("Connect")</Button>
|
|
|
|
@if (OfflineModeAvailable)
|
|
{
|
|
<Button OnClick="() => OfflineMode()">@LocalizationService.GetString("Offline")</Button>
|
|
}
|
|
</Flex>
|
|
</FormItem>
|
|
</Form>
|
|
|
|
<Divider Text="@LocalizationService.GetString("Discovered")" Orientation="DividerOrientation.Center" />
|
|
|
|
<AntList DataSource="DiscoveredServers">
|
|
<ChildContent>
|
|
<ListItem OnClick="() => SelectServer(context.Address)">
|
|
<ListItemMeta Title="@context.Name" Description="@context.Address.ToString()"/>
|
|
</ListItem>
|
|
</ChildContent>
|
|
|
|
<LoadMore>
|
|
<Flex Justify="FlexJustify.Center" Class="load-more">
|
|
@if (BeaconActive)
|
|
{
|
|
<Dropdown Trigger="@(new [] { Trigger.Hover })">
|
|
<Overlay>
|
|
<Menu>
|
|
<MenuItem Key="Cancel" OnClick="CancelBeacon">@LocalizationService.GetString("Cancel")</MenuItem>
|
|
</Menu>
|
|
</Overlay>
|
|
<ChildContent>
|
|
<Button Type="ButtonType.Primary" Loading="true" Disabled>@LocalizationService.GetString("Scanning")</Button>
|
|
</ChildContent>
|
|
</Dropdown>
|
|
}
|
|
else
|
|
{
|
|
<Button Type="ButtonType.Primary" OnClick="() => ActivateBeacon()">@LocalizationService.GetString("Rescan")</Button>
|
|
}
|
|
</Flex>
|
|
</LoadMore>
|
|
</AntList>
|
|
|
|
@code {
|
|
[Parameter] public EventCallback<Uri> OnSelected { get; set; }
|
|
[Parameter] public bool Connecting { get; set; } = false;
|
|
bool IsInitializing = false;
|
|
|
|
bool BeaconActive = false;
|
|
bool OfflineModeAvailable = false;
|
|
|
|
Uri ServerAddress;
|
|
|
|
AuthRequest Model = new();
|
|
List<DiscoveredServer> DiscoveredServers = new();
|
|
private CancellationTokenSource DiscoveryToken = new CancellationTokenSource();
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
IsInitializing = true;
|
|
|
|
ServerAddress = ConnectionClient.GetServerAddress();
|
|
|
|
Connecting = true;
|
|
OfflineModeAvailable = await AuthenticationService.OfflineModeAvailableAsync();
|
|
|
|
BeaconClient.OnBeaconResponse += OnBeaconResponse;
|
|
|
|
if (!OfflineModeAvailable)
|
|
{
|
|
ActivateBeacon();
|
|
}
|
|
|
|
Connecting = false;
|
|
IsInitializing = false;
|
|
}
|
|
|
|
private void OnBeaconResponse(object sender, BeaconResponseArgs e)
|
|
{
|
|
var discoveredServer = new DiscoveredServer(e.Message, e.EndPoint);
|
|
|
|
if (DiscoveredServers.All(s => s.Address != discoveredServer.Address))
|
|
{
|
|
DiscoveredServers.Add(discoveredServer);
|
|
InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
|
|
async Task SelectServer(Uri serverAddress)
|
|
{
|
|
await BeaconClient.StopProbeAsync();
|
|
|
|
BeaconActive = false;
|
|
|
|
if (OnSelected.HasDelegate)
|
|
await OnSelected.InvokeAsync(serverAddress);
|
|
}
|
|
|
|
void OfflineMode()
|
|
{
|
|
AuthenticationService.LoginOffline();
|
|
NavigationManager.NavigateTo("/", forceLoad: true);
|
|
}
|
|
|
|
void CancelBeacon()
|
|
{
|
|
DiscoveryToken?.Cancel();
|
|
}
|
|
|
|
async Task ActivateBeacon()
|
|
{
|
|
try
|
|
{
|
|
BeaconActive = true;
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
// give the UI a chance to render:
|
|
await Task.Yield();
|
|
|
|
if ((DiscoveryToken?.TryReset() ?? false) == false)
|
|
{
|
|
DiscoveryToken = new();
|
|
}
|
|
|
|
await BeaconClient.StartProbeAsync(cancellationToken: DiscoveryToken.Token);
|
|
await Task.Delay(10000, DiscoveryToken.Token);
|
|
await BeaconClient.StopProbeAsync();
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// ignore, handled in finally
|
|
}
|
|
finally
|
|
{
|
|
BeaconClient.CleanupProbe();
|
|
BeaconActive = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
BeaconClient.OnBeaconResponse -= OnBeaconResponse;
|
|
DiscoveryToken?.Cancel();
|
|
DiscoveryToken?.Dispose();
|
|
}
|
|
} |