423 lines
28 KiB
XML
423 lines
28 KiB
XML
<Window xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
x:Class="Lumi.Companion.App.MainWindow"
|
|
Title="Lumi Companion"
|
|
Icon="/Assets/Lumi.Companion.ico"
|
|
Width="1120" Height="760" MinWidth="900" MinHeight="620"
|
|
WindowStartupLocation="CenterScreen">
|
|
<Grid ColumnDefinitions="248,*">
|
|
<Border Grid.Column="0" Background="#F4F7F8" Padding="22,24">
|
|
<Grid RowDefinitions="Auto,Auto,*,Auto">
|
|
<StackPanel Orientation="Horizontal" Spacing="11">
|
|
<Border Width="34" Height="34" CornerRadius="9" Background="#28B7C8">
|
|
<Path Data="M 17,7 L 27,17 L 17,27 L 7,17 Z" Fill="White" Stretch="None" />
|
|
</Border>
|
|
<StackPanel VerticalAlignment="Center" Spacing="0">
|
|
<TextBlock Text="LUMI" Classes="eyebrow" />
|
|
<TextBlock Text="Companion" FontWeight="SemiBold" FontSize="16" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
|
|
<Border Grid.Row="1" Margin="0,25,0,20" Padding="11,9" CornerRadius="9" Background="#E6EEF0">
|
|
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="9">
|
|
<Border x:Name="StatusMark" Width="10" Height="10" CornerRadius="5" Background="#A96612" VerticalAlignment="Center" />
|
|
<StackPanel Grid.Column="1" Spacing="1">
|
|
<TextBlock x:Name="StatusLabel" Text="Setup required" FontSize="13" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="StatusSymbol" Text="○ Incomplete" FontSize="11" Foreground="{DynamicResource LumiMutedBrush}" />
|
|
</StackPanel>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<Grid Grid.Row="2" RowDefinitions="Auto,*,Auto">
|
|
<StackPanel Spacing="4">
|
|
<Button x:Name="OverviewNav" Classes="nav selected" Content="Overview" Tag="Overview" />
|
|
<Button x:Name="StreamTestingNav" Classes="nav" Content="Stream testing" Tag="StreamTesting" />
|
|
</StackPanel>
|
|
|
|
<ScrollViewer Grid.Row="1" Margin="0,14,0,14" VerticalScrollBarVisibility="Auto">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="PLUGINS" Classes="eyebrow" Margin="12,0,0,4" />
|
|
<StackPanel x:Name="PluginNavigation" Spacing="4" />
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<StackPanel Grid.Row="2" x:Name="TechnicalNavigation">
|
|
<Border Height="1" Background="{DynamicResource LumiBorderBrush}" Margin="0,0,0,8" />
|
|
<Button x:Name="ConnectionNav" Classes="nav" Content="Connection & device" Tag="Connection" />
|
|
<Button x:Name="LogsNav" Classes="nav" Content="Logs & diagnostics" Tag="Logs" />
|
|
<Button x:Name="SettingsNav" Classes="nav" Content="Settings" Tag="Settings" />
|
|
</StackPanel>
|
|
</Grid>
|
|
|
|
<TextBlock Grid.Row="3" Text="Runs quietly in the notification area" Classes="muted" FontSize="11" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<Grid Grid.Column="1">
|
|
<ScrollViewer x:Name="OverviewPage">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="AT A GLANCE" Classes="eyebrow" />
|
|
<TextBlock Text="Overview" Classes="pageTitle" />
|
|
<TextBlock x:Name="OverviewDetail" Text="Checking what is ready…" Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
|
|
<Border Classes="soft" Padding="22">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock x:Name="NextActionTitle" Text="Pair this computer" Classes="sectionTitle" />
|
|
<TextBlock x:Name="NextActionDetail" Text="Use a one-time pairing package from Lumi to connect this streaming computer." Classes="muted" MaxWidth="520" />
|
|
</StackPanel>
|
|
<Button Grid.Column="1" x:Name="NextActionButton" Classes="primary" Content="Choose pairing package" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<Border x:Name="UpdatePanel" Classes="soft" Padding="18" IsVisible="False">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="20">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock x:Name="UpdateTitle" Text="Companion update available" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="UpdateDetail" Text="A verified update is ready." Classes="muted" />
|
|
</StackPanel>
|
|
<Button Grid.Column="1" x:Name="ApplyUpdateButton" Classes="primary" Content="Update Companion" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<Border x:Name="OverviewBridgeUpdatePanel" Background="#FFF2D6" BorderBrush="#D58A1F" BorderThickness="1" CornerRadius="12" Padding="18" IsVisible="False">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="20">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock Text="Update OBS Bridge" FontWeight="Bold" Foreground="#764600" />
|
|
<TextBlock x:Name="OverviewBridgeUpdateDetail" Text="The OBS integration loaded by OBS is older than the version bundled with Companion." TextWrapping="Wrap" Foreground="#764600" />
|
|
</StackPanel>
|
|
<Button Grid.Column="1" x:Name="OverviewUpdateBridgeButton" Classes="primary" Content="Update OBS Bridge" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<StackPanel Spacing="12">
|
|
<TextBlock Text="Setup progress" Classes="sectionTitle" />
|
|
<Grid ColumnDefinitions="*,*,*" ColumnSpacing="12">
|
|
<Border Classes="card">
|
|
<StackPanel Spacing="7">
|
|
<TextBlock x:Name="PairingStepSymbol" Text="○" FontSize="20" />
|
|
<TextBlock Text="Lumi connection" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="PairingStepDetail" Text="Not paired" Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Grid.Column="1" Classes="card">
|
|
<StackPanel Spacing="7">
|
|
<TextBlock x:Name="ObsStepSymbol" Text="○" FontSize="20" />
|
|
<TextBlock Text="OBS integration" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="ObsStepDetail" Text="Not installed" Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Grid.Column="2" Classes="card">
|
|
<StackPanel Spacing="7">
|
|
<TextBlock x:Name="TestStepSymbol" Text="○" FontSize="20" />
|
|
<TextBlock Text="Full path test" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="TestStepDetail" Text="Not run" Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
</Border>
|
|
</Grid>
|
|
</StackPanel>
|
|
|
|
<Border Classes="soft">
|
|
<TextBlock Text="Lumi Companion never runs speech recognition on this streaming computer. Audio stays in bounded memory and is sent to your paired Lumi host." Classes="muted" />
|
|
</Border>
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<ScrollViewer x:Name="StreamTestingPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="PRIVATE OUTPUT" Classes="eyebrow" />
|
|
<TextBlock Text="Stream testing" Classes="pageTitle" />
|
|
<TextBlock Text="Send the real OBS stream to Lumi's private test receiver, inspect it in the Admin page, then restore the exact normal streaming service automatically." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
<Border Background="#FFF2D6" BorderBrush="#D58A1F" BorderThickness="1" CornerRadius="12" Padding="18">
|
|
<StackPanel Spacing="5">
|
|
<TextBlock Text="Never start this while publicly live" FontWeight="Bold" Foreground="#764600" />
|
|
<TextBlock Text="Companion refuses to redirect active streaming or recording. While the test is active, the status below remains unmistakable and the prior OBS service is kept in an encrypted current-user recovery file." TextWrapping="Wrap" Foreground="#764600" />
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Classes="card">
|
|
<StackPanel Spacing="16">
|
|
<StackPanel Spacing="5">
|
|
<TextBlock x:Name="StreamTestStatusTitle" Text="Ready to check" Classes="sectionTitle" />
|
|
<TextBlock x:Name="StreamTestStatusDetail" Text="Start only while OBS is idle." Classes="muted" TextWrapping="Wrap" />
|
|
</StackPanel>
|
|
<Grid ColumnDefinitions="*,*,*" ColumnSpacing="12">
|
|
<Border Classes="soft"><StackPanel Spacing="4"><TextBlock Text="OBS bitrate" Classes="muted" FontSize="11" /><TextBlock x:Name="StreamTestBitrateText" Text="—" FontWeight="SemiBold" /></StackPanel></Border>
|
|
<Border Grid.Column="1" Classes="soft"><StackPanel Spacing="4"><TextBlock Text="Dropped frames" Classes="muted" FontSize="11" /><TextBlock x:Name="StreamTestDroppedText" Text="—" FontWeight="SemiBold" /></StackPanel></Border>
|
|
<Border Grid.Column="2" Classes="soft"><StackPanel Spacing="4"><TextBlock Text="Congestion" Classes="muted" FontSize="11" /><TextBlock x:Name="StreamTestCongestionText" Text="—" FontWeight="SemiBold" /></StackPanel></Border>
|
|
</Grid>
|
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
|
<Button x:Name="StartStreamTestButton" Classes="primary" Content="Start private stream test" />
|
|
<Button x:Name="StopStreamTestButton" Classes="secondary" Content="End test and restore OBS" IsEnabled="False" />
|
|
<Button x:Name="OpenStreamTestWebButton" Classes="secondary" Content="Open stream viewer" IsVisible="False" />
|
|
<Button x:Name="RepairStreamTestButton" Classes="secondary" Content="Repair restoration" IsVisible="False" />
|
|
</StackPanel>
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="5">
|
|
<TextBlock Text="Where to watch" FontWeight="SemiBold" />
|
|
<TextBlock Text="Open Admin → Stream testing in Lumi WebUI for the private player, quality control, receiver facts, warnings, and recovery timeline." Classes="muted" TextWrapping="Wrap" />
|
|
</StackPanel>
|
|
</Border>
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<ScrollViewer x:Name="TranscriptionPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="25">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="CAPTURE" Classes="eyebrow" />
|
|
<TextBlock Text="Transcription" Classes="pageTitle" />
|
|
<TextBlock Text="Choose the OBS microphone Lumi should caption. Source identity remains stable if you rename it." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
<Border Classes="card">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="24">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock Text="Generate and include captions" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="TranscriptionEnabledDetail" Text="Speech recognition and caption inclusion are enabled." Classes="muted" TextWrapping="Wrap" />
|
|
</StackPanel>
|
|
<ToggleSwitch Grid.Column="1" x:Name="TranscriptionEnabledToggle" OffContent="Off" OnContent="On" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
<StackPanel Spacing="8">
|
|
<TextBlock Text="Primary microphone" FontWeight="SemiBold" />
|
|
<ComboBox x:Name="SourcePicker" IsEnabled="False" PlaceholderText="Open OBS after installing the managed integration" MinWidth="420" HorizontalAlignment="Left" />
|
|
<TextBlock x:Name="SourceHelp" Text="No OBS source list is available yet." Classes="muted" />
|
|
</StackPanel>
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="7">
|
|
<TextBlock Text="Optional second microphone" FontWeight="SemiBold" />
|
|
<TextBlock Text="The protocol supports more than one source, but source overlap policy remains disabled until the primary path is validated." Classes="muted" />
|
|
</StackPanel>
|
|
</Border>
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<ScrollViewer x:Name="TestPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="SAFE CHECK" Classes="eyebrow" />
|
|
<TextBlock Text="Transcription test" Classes="pageTitle" />
|
|
<TextBlock Text="Checks the selected OBS source, secure connection, model readiness, and safe caption return path. You do not need to speak, and nothing is sent to Twitch." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
<Button x:Name="RunTestButton" Classes="primary" Content="Run full path test" HorizontalAlignment="Left" />
|
|
<StackPanel x:Name="TestStagesPanel" Spacing="8" />
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="5">
|
|
<TextBlock Text="Simulated outgoing caption" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="SimulatedCaption" Text="A real caption will appear here only after every upstream stage passes." Classes="muted" FontStyle="Italic" />
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Classes="card">
|
|
<StackPanel Spacing="16">
|
|
<StackPanel Spacing="5">
|
|
<TextBlock Text="ACCURACY & LATENCY" Classes="eyebrow" />
|
|
<TextBlock Text="Dedicated transcription test" Classes="sectionTitle" />
|
|
<TextBlock Text="Speak naturally for as long as needed. End the test yourself, or Lumi will finalize it after 10 seconds of silence. Nothing is sent to Twitch." Classes="muted" />
|
|
</StackPanel>
|
|
<Grid ColumnDefinitions="Auto,Auto,*,Auto" ColumnSpacing="10">
|
|
<Button x:Name="StartBenchmarkButton" Classes="primary" Content="Start dedicated test" />
|
|
<Button Grid.Column="1" x:Name="StopBenchmarkButton" Classes="secondary" Content="End test" IsEnabled="False" />
|
|
<ProgressBar Grid.Column="2" x:Name="VoiceLevelMeter" Minimum="-60" Maximum="0" Value="-60" Height="12" MinWidth="220" VerticalAlignment="Center" Foreground="{DynamicResource LumiDangerBrush}" />
|
|
<TextBlock Grid.Column="3" x:Name="VoiceLevelText" Text="-60 dBFS" Classes="muted" FontSize="11" VerticalAlignment="Center" MinWidth="58" />
|
|
</Grid>
|
|
<TextBlock Text="Input level: green from -30 to -12 dBFS; orange within 10 dB outside that range; red otherwise." Classes="muted" FontSize="11" />
|
|
<TextBlock x:Name="BenchmarkStatusText" Text="Not started." Classes="muted" />
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="5">
|
|
<TextBlock Text="Measured transcript" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="BenchmarkTranscript" Text="Finalized speech will appear here." Classes="muted" TextWrapping="Wrap" />
|
|
</StackPanel>
|
|
</Border>
|
|
<StackPanel Spacing="8">
|
|
<TextBlock Text="Latency" FontWeight="SemiBold" />
|
|
<WrapPanel x:Name="LatencyStatsPanel" Orientation="Horizontal" />
|
|
</StackPanel>
|
|
<StackPanel Spacing="8">
|
|
<TextBlock Text="Final confidence" FontWeight="SemiBold" />
|
|
<WrapPanel x:Name="ConfidenceStatsPanel" Orientation="Horizontal" />
|
|
</StackPanel>
|
|
<TextBlock Text="Low and high 1% values are tail averages. Confidence is included only after an utterance is finalized." Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
</Border>
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
|
|
<ScrollViewer x:Name="SongOverlayPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="MEDIA" Classes="eyebrow" />
|
|
<TextBlock Text="Song Overlay" Classes="pageTitle" />
|
|
<TextBlock Text="Spotify is the first media provider. The provider contract remains generic so later services can use the same event and overlay pipeline." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
|
|
<Border Classes="soft">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="20">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock x:Name="SongOverlayStatusTitle" Text="Starting" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="SongOverlayStatusDetail" Text="Waiting for the media provider…" Classes="muted" />
|
|
<TextBlock x:Name="SongOverlayCurrentTrack" Text="No active song" Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
<ToggleSwitch Grid.Column="1" x:Name="SongOverlayEnabledToggle" OffContent="Off" OnContent="On" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
|
|
<StackPanel Spacing="10">
|
|
<TextBlock Text="Lumi authentication" Classes="sectionTitle" />
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock x:Name="SongOverlayLumiAuthenticationText" Text="Uses the Companion device pairing" FontWeight="SemiBold" />
|
|
<TextBlock Text="Song Overlay inherits the protected Companion credential automatically. Revoking or forgetting this Companion also revokes plugin access; no separate plugin key is needed." Classes="muted" />
|
|
</StackPanel>
|
|
</Border>
|
|
</StackPanel>
|
|
|
|
<StackPanel Spacing="12">
|
|
<TextBlock Text="Playback provider" Classes="sectionTitle" />
|
|
<Grid ColumnDefinitions="150,*" RowDefinitions="Auto,Auto,Auto" RowSpacing="10" ColumnSpacing="12">
|
|
<TextBlock Text="Provider" Classes="muted" VerticalAlignment="Center" />
|
|
<ComboBox Grid.Column="1" x:Name="SongOverlayProviderPicker" SelectedIndex="0" IsEnabled="False">
|
|
<ComboBoxItem Content="Spotify" Tag="spotify" />
|
|
</ComboBox>
|
|
<TextBlock Grid.Row="1" Text="Recovery heartbeat" Classes="muted" VerticalAlignment="Center" />
|
|
<NumericUpDown Grid.Row="1" Grid.Column="1" x:Name="SongOverlayHeartbeatBox" Minimum="15" Maximum="300" Increment="5" FormatString="0 seconds" HorizontalAlignment="Left" Width="160" />
|
|
<TextBlock Grid.Row="2" Text="Seek sensitivity" Classes="muted" VerticalAlignment="Center" />
|
|
<NumericUpDown Grid.Row="2" Grid.Column="1" x:Name="SongOverlaySeekBox" Minimum="500" Maximum="10000" Increment="250" FormatString="0 ms" HorizontalAlignment="Left" Width="160" />
|
|
</Grid>
|
|
<CheckBox x:Name="SongOverlayCoverToggle" Content="Send cover art only with track metadata" />
|
|
<CheckBox x:Name="SongOverlaySearchLinkToggle" Content="Use a Spotify search link when an exact song link is unavailable" />
|
|
</StackPanel>
|
|
|
|
<Border Classes="card">
|
|
<StackPanel Spacing="12">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock Text="SPOTIFY-SPECIFIC" Classes="eyebrow" />
|
|
<TextBlock Text="Optional metadata enrichment" Classes="sectionTitle" />
|
|
<TextBlock Text="Windows normally supplies title, artist, album, timeline and artwork. Connecting your own Spotify application adds an exact link, release year and official artwork when available. Spotify is contacted only when track metadata changes or needs recovery." Classes="muted" />
|
|
</StackPanel>
|
|
<TextBox x:Name="SongOverlaySpotifyClientIdBox" PlaceholderText="Spotify application Client ID" />
|
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
|
<Button x:Name="ConnectSongOverlaySpotifyButton" Classes="secondary" Content="Connect Spotify metadata" />
|
|
<Button x:Name="DisconnectSongOverlaySpotifyButton" Classes="secondary" Content="Disconnect" />
|
|
</StackPanel>
|
|
<TextBlock x:Name="SongOverlaySpotifyStatus" Text="Not connected. Core playback detection still works through Windows." Classes="muted" />
|
|
</StackPanel>
|
|
</Border>
|
|
|
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
|
<Button x:Name="SaveSongOverlayButton" Classes="primary" Content="Save Song Overlay" />
|
|
<Button x:Name="SendSongOverlayStateButton" Classes="secondary" Content="Send current song now" />
|
|
</StackPanel>
|
|
<TextBlock x:Name="SongOverlayFeedback" Classes="muted" />
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<ScrollViewer x:Name="ConnectionPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="DEVICE" Classes="eyebrow" />
|
|
<TextBlock Text="Connection & device" Classes="pageTitle" />
|
|
<TextBlock Text="The device credential is protected for your Windows account and never shared with OBS." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
<Grid ColumnDefinitions="150,*" RowDefinitions="Auto,Auto,Auto" RowSpacing="12">
|
|
<TextBlock Text="Computer" Classes="muted" /><TextBlock Grid.Column="1" x:Name="DeviceNameText" Text="Not paired" FontWeight="SemiBold" />
|
|
<TextBlock Grid.Row="1" Text="Lumi host" Classes="muted" /><TextBlock Grid.Row="1" Grid.Column="1" x:Name="HostText" Text="—" />
|
|
<TextBlock Grid.Row="2" Text="Last connected" Classes="muted" /><TextBlock Grid.Row="2" Grid.Column="1" x:Name="LastConnectedText" Text="Never" />
|
|
</Grid>
|
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
|
<Button x:Name="ReconnectButton" Classes="secondary" Content="Retry connection" />
|
|
<Button x:Name="PairButton" Classes="secondary" Content="Choose pairing package" />
|
|
<Button x:Name="OpenWebButton" Classes="secondary" Content="Open Lumi WebUI" />
|
|
</StackPanel>
|
|
<Border x:Name="ConnectionBridgeUpdatePanel" Background="#FFF2D6" BorderBrush="#D58A1F" BorderThickness="1" CornerRadius="12" Padding="18" IsVisible="False">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="20">
|
|
<StackPanel Spacing="4">
|
|
<TextBlock Text="OBS Bridge update required" FontWeight="Bold" Foreground="#764600" />
|
|
<TextBlock x:Name="ConnectionBridgeUpdateDetail" Text="Close OBS before updating the managed integration." TextWrapping="Wrap" Foreground="#764600" />
|
|
</StackPanel>
|
|
<Button Grid.Column="1" x:Name="ConnectionUpdateBridgeButton" Classes="primary" Content="Update OBS Bridge" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="10">
|
|
<TextBlock Text="Managed OBS integration" FontWeight="SemiBold" />
|
|
<TextBlock x:Name="BridgeStatusText" Text="Checking the bundled integration…" Classes="muted" />
|
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
|
<Button x:Name="InstallBridgeButton" Classes="primary" Content="Install integration" />
|
|
<Button x:Name="RemoveBridgeButton" Classes="secondary" Content="Remove integration" />
|
|
</StackPanel>
|
|
<TextBlock Text="Close OBS before install, repair, or removal. Restart OBS afterward so it can load the verified plugin." Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Classes="soft">
|
|
<StackPanel Spacing="8">
|
|
<TextBlock Text="Remove this device" FontWeight="SemiBold" />
|
|
<TextBlock Text="Removes the local credential. You can also revoke this computer from Lumi." Classes="muted" />
|
|
<Button x:Name="ForgetButton" Classes="secondary" Content="Forget this device" HorizontalAlignment="Left" />
|
|
</StackPanel>
|
|
</Border>
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<ScrollViewer x:Name="LogsPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="24">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="DIAGNOSTICS" Classes="eyebrow" />
|
|
<TextBlock Text="Logs & diagnostics" Classes="pageTitle" />
|
|
<TextBlock Text="Short-lived diagnostic logs help explain connection and delivery failures. Raw audio is never written to disk." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
<Button x:Name="OpenLogsButton" Classes="secondary" Content="Open logs folder" HorizontalAlignment="Left" />
|
|
<Border Background="#182026" CornerRadius="12" Padding="16" MinHeight="230">
|
|
<StackPanel x:Name="RecentLogsPanel" Spacing="6">
|
|
<TextBlock Text="Waiting for companion events…" Foreground="#CFDADD" FontFamily="Consolas" FontSize="12" />
|
|
</StackPanel>
|
|
</Border>
|
|
<TextBlock Text="Logs are retained for 7 days and capped at 256 MiB. Caption text may appear in diagnostics during testing or troubleshooting." Classes="muted" FontSize="12" />
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
|
|
<ScrollViewer x:Name="SettingsPage" IsVisible="False">
|
|
<StackPanel Margin="44,38,52,48" MaxWidth="760" HorizontalAlignment="Left" Spacing="25">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="PREFERENCES" Classes="eyebrow" />
|
|
<TextBlock Text="Settings" Classes="pageTitle" />
|
|
<TextBlock Text="Only controls useful on the streaming computer live here. Model and server administration stay in Lumi." Classes="muted" FontSize="15" />
|
|
</StackPanel>
|
|
<StackPanel Spacing="16">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="24">
|
|
<StackPanel Spacing="3"><TextBlock Text="Start with Windows" FontWeight="SemiBold" /><TextBlock Text="Keep Lumi Companion ready in the notification area after sign-in." Classes="muted" /></StackPanel>
|
|
<ToggleSwitch Grid.Column="1" x:Name="AutoStartToggle" OffContent="Off" OnContent="On" />
|
|
</Grid>
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="24">
|
|
<StackPanel Spacing="3"><TextBlock Text="Start companion features with OBS" FontWeight="SemiBold" /><TextBlock Text="Prepare selected features when OBS becomes available." Classes="muted" /></StackPanel>
|
|
<ToggleSwitch Grid.Column="1" x:Name="StartWithObsToggle" OffContent="Off" OnContent="On" />
|
|
</Grid>
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="24">
|
|
<StackPanel Spacing="3"><TextBlock Text="Advanced mode" FontWeight="SemiBold" /><TextBlock Text="Reveal protocol and component details useful for troubleshooting." Classes="muted" /></StackPanel>
|
|
<ToggleSwitch Grid.Column="1" x:Name="AdvancedToggle" OffContent="Off" OnContent="On" />
|
|
</Grid>
|
|
</StackPanel>
|
|
<Border x:Name="AdvancedPanel" Classes="soft" IsVisible="False">
|
|
<StackPanel Spacing="6">
|
|
<TextBlock Text="Advanced details" FontWeight="SemiBold" />
|
|
<TextBlock Text="Protocol v1 · bounded in-memory audio · secure WebSocket transport · server-hosted inference" Classes="muted" />
|
|
</StackPanel>
|
|
</Border>
|
|
<Border Classes="soft">
|
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="20">
|
|
<StackPanel Spacing="4"><TextBlock Text="Companion updates" FontWeight="SemiBold" /><TextBlock x:Name="UpdateStatusText" Text="Checking for updates…" Classes="muted" /><TextBlock Text="Current version" Classes="muted" FontSize="11" /><TextBlock x:Name="CurrentVersionText" Text="—" FontSize="12" /></StackPanel>
|
|
<Button Grid.Column="1" x:Name="CheckUpdateButton" Classes="secondary" Content="Check now" VerticalAlignment="Center" />
|
|
</Grid>
|
|
</Border>
|
|
<Button x:Name="SaveSettingsButton" Classes="primary" Content="Save preferences" HorizontalAlignment="Left" />
|
|
<TextBlock x:Name="SettingsFeedback" Classes="muted" />
|
|
</StackPanel>
|
|
</ScrollViewer>
|
|
</Grid>
|
|
</Grid>
|
|
</Window>
|