+
@Text
- @Client.State.Value.ToString()
- @Client.Gateway
- Latency: @(Client.Latency.Value)ms
+ @if (Client != null)
+ {
+ Live control: @Client.State.Value.ToString()
+ @Client.Gateway
+ Latency: @(Client.Latency.Value)ms
+ }
+ else if (Online)
+ {
+ Online
+ Live control idle
+ }
+ else
+ {
+ Offline
+ }
+ @if (Shared)
+ {
+
+ Shared with you
+ }
@@ -16,4 +33,4 @@
.child-div-align-center > div {
align-self: center;
}
-
\ No newline at end of file
+
diff --git a/Desktop/Ui/Pages/Dash/Components/StatePart.razor.cs b/Desktop/Ui/Pages/Dash/Components/StatePart.razor.cs
index 2dc6ebe..0e786c6 100644
--- a/Desktop/Ui/Pages/Dash/Components/StatePart.razor.cs
+++ b/Desktop/Ui/Pages/Dash/Components/StatePart.razor.cs
@@ -1,47 +1,93 @@
-using System.ComponentModel;
-using LucHeart.WebsocketLibrary;
+using System.ComponentModel;
using Microsoft.AspNetCore.Components;
+using LucHeart.WebsocketLibrary;
using OpenShock.SDK.CSharp.Live;
-using OpenShock.SDK.CSharp.Live.LiveControlModels;
using Color = MudBlazor.Color;
namespace OpenShock.Desktop.Ui.Pages.Dash.Components;
public partial class StatePart : ComponentBase, IAsyncDisposable
{
+ ///
+ /// The active live control client for this hub, or null when no live control connection is open.
+ /// Because connections are opened lazily and closed when idle, this switches between null and a client over time.
+ ///
[Parameter]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
- public required IOpenShockLiveControlClient Client { get; set; }
-
+ public IOpenShockLiveControlClient? Client { get; set; }
+
+ ///
+ /// Whether the hub is reported online by the backend (independent of whether a live control socket is open).
+ ///
+ [Parameter]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
+ public bool Online { get; set; }
+
[Parameter]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public required string Text { get; set; }
-
- private bool _disposed = false;
- private IAsyncDisposable _stateSubscription = null!;
- private IAsyncDisposable _latencySubscription = null!;
-
- private Color GetConnectionStateColor() =>
- Client.State.Value switch
- {
- WebsocketConnectionState.Connected => Color.Success,
- WebsocketConnectionState.Connecting => Color.Warning,
- WebsocketConnectionState.WaitingForReconnect => Color.Warning,
- _ => Color.Error
- };
-
- protected override async Task OnInitializedAsync()
+
+ ///
+ /// Whether this hub is shared with the current user by another owner (as opposed to owned).
+ ///
+ [Parameter]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
+ public bool Shared { get; set; }
+
+ private bool _disposed;
+ private IOpenShockLiveControlClient? _subscribedClient;
+ private IAsyncDisposable? _stateSubscription;
+ private IAsyncDisposable? _latencySubscription;
+
+ private Color GetConnectionStateColor()
{
+ if (Client != null)
+ return Client.State.Value switch
+ {
+ WebsocketConnectionState.Connected => Color.Success,
+ WebsocketConnectionState.Connecting => Color.Warning,
+ WebsocketConnectionState.WaitingForReconnect => Color.Warning,
+ _ => Color.Error
+ };
+
+ return Online ? Color.Info : Color.Dark;
+ }
+
+ protected override async Task OnParametersSetAsync()
+ {
+ // The Client parameter switches between null and a client as connections open / close. Keep our subscriptions
+ // pointed at the current client.
+ if (ReferenceEquals(_subscribedClient, Client)) return;
+
+ await UnsubscribeAsync();
+ _subscribedClient = Client;
+
+ if (Client == null) return;
+
_stateSubscription = await Client.State.Updated.SubscribeAsync(_ => InvokeAsync(StateHasChanged));
_latencySubscription = await Client.Latency.Updated.SubscribeAsync(_ => InvokeAsync(StateHasChanged));
}
-
+
+ private async Task UnsubscribeAsync()
+ {
+ if (_stateSubscription != null)
+ {
+ await _stateSubscription.DisposeAsync();
+ _stateSubscription = null;
+ }
+
+ if (_latencySubscription != null)
+ {
+ await _latencySubscription.DisposeAsync();
+ _latencySubscription = null;
+ }
+ }
+
public async ValueTask DisposeAsync()
{
if (_disposed) return;
_disposed = true;
-
- await _stateSubscription.DisposeAsync();
- await _latencySubscription.DisposeAsync();
+
+ await UnsubscribeAsync();
}
-}
\ No newline at end of file
+}
diff --git a/Desktop/Ui/Pages/Dash/SideBar.razor b/Desktop/Ui/Pages/Dash/SideBar.razor
index e987dfa..00a857f 100644
--- a/Desktop/Ui/Pages/Dash/SideBar.razor
+++ b/Desktop/Ui/Pages/Dash/SideBar.razor
@@ -97,21 +97,14 @@
@foreach (var device in Api.Hubs.Value)
{
- if (LiveControlManager.LiveControlClients.TryGetValue(device.Id, out var client))
- {
-
- }
- else
- {
-
- @device.Name.Truncate(13)
-
-
-
-
- }
+
+ }
+
+ @if (Api.SharedOwners.Value.Count > 0)
+ {
+
}
diff --git a/Desktop/Ui/Pages/Dash/Tabs/DashboardTab.razor b/Desktop/Ui/Pages/Dash/Tabs/DashboardTab.razor
index a371919..5e10d95 100644
--- a/Desktop/Ui/Pages/Dash/Tabs/DashboardTab.razor
+++ b/Desktop/Ui/Pages/Dash/Tabs/DashboardTab.razor
@@ -57,19 +57,14 @@
@foreach (var device in Api.Hubs.Value)
{
- if (LiveControlManager.LiveControlClients.TryGetValue(device.Id, out var client))
- {
-