Some checks failed
CI / build-and-test (push) Failing after 30s
Task 39: 5-column participants table - state LED, name+codec caption, 5-bar audio meter, mono output name, ISO pill. Row height 52, full-row active-speaker tint (no left stripe). New converter LevelThresholdConverter, OutputName property on ParticipantViewModel. Task 40: Ctrl+K / Ctrl+P command palette - chromeless centered floating window, fuzzy Contains match across Label/Category/Keywords, arrow nav, Enter invoke, Esc close. Quick/Teams/Network/App categories cover top operator verbs and theme switching. Also: log startup exceptions to Serilog before the modal MessageBox fires - much better triage signal than user-pasted dialog text.
933 lines
57 KiB
XML
933 lines
57 KiB
XML
<Window x:Class="TeamsISO.App.MainWindow"
|
||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||
xmlns:vm="clr-namespace:TeamsISO.App.ViewModels"
|
||
xmlns:conv="clr-namespace:TeamsISO.App.Converters"
|
||
mc:Ignorable="d"
|
||
Title="TeamsISO"
|
||
Width="1280" Height="780"
|
||
MinWidth="980" MinHeight="640"
|
||
WindowStartupLocation="CenterScreen"
|
||
Background="{DynamicResource Wd.Canvas}"
|
||
Foreground="{DynamicResource Wd.Text.Primary}"
|
||
UseLayoutRounding="True"
|
||
SnapsToDevicePixels="True"
|
||
TextOptions.TextRenderingMode="ClearType"
|
||
TextOptions.TextFormattingMode="Display"
|
||
d:DataContext="{d:DesignInstance Type=vm:MainViewModel}">
|
||
<!--
|
||
v2 SHELL — "Studio Terminal"
|
||
(Approved 2026-05-13. Shape brief at docs/shapes/2026-05-13-teamsiso-v2-studio-terminal.md)
|
||
|
||
Default Windows title bar (no chromeless WindowChrome). The 32px header
|
||
below it carries the brand mark, wordmark, and three icon buttons:
|
||
⌘K (command palette), theme toggle, settings drawer. Below that, a
|
||
single transport strip carries the operator's at-a-glance status.
|
||
The participants area is the canvas — no rail, no permanent side
|
||
panel, no footer. The meeting bar at the bottom renders ONLY when
|
||
Teams is in a call.
|
||
-->
|
||
|
||
<Window.Resources>
|
||
<conv:BoolToVisibilityConverter x:Key="BoolToVis"
|
||
TrueValue="Visible"
|
||
FalseValue="Collapsed"/>
|
||
<conv:BoolToVisibilityConverter x:Key="BoolToVisInverse"
|
||
TrueValue="Collapsed"
|
||
FalseValue="Visible"/>
|
||
<conv:EnumDescriptionConverter x:Key="EnumDesc"/>
|
||
<conv:LevelThresholdConverter x:Key="LevelGate"/>
|
||
</Window.Resources>
|
||
|
||
<Window.InputBindings>
|
||
<KeyBinding Key="F1" Command="{Binding ShowHelpCommand}"/>
|
||
<KeyBinding Key="S" Modifiers="Ctrl+Shift" Command="{Binding StopAllIsosCommand}"/>
|
||
<KeyBinding Key="R" Modifiers="Ctrl" Command="{Binding RefreshDiscoveryCommand}"/>
|
||
<KeyBinding Key="T" Modifiers="Ctrl" Command="{Binding ToggleThemeCommand}"/>
|
||
<!-- Ctrl+K (and Ctrl+P alias) — open the v2 command palette. The
|
||
KeyBinding fires on the window; the handler is wired via the
|
||
palette button's Click in the header. -->
|
||
<KeyBinding Key="K" Modifiers="Ctrl" Command="{Binding OpenCommandPaletteCommand}"/>
|
||
<KeyBinding Key="P" Modifiers="Ctrl" Command="{Binding OpenCommandPaletteCommand}"/>
|
||
<KeyBinding Key="NumPad1" Command="{Binding ToggleByIndexCommand}" CommandParameter="1"/>
|
||
<KeyBinding Key="NumPad2" Command="{Binding ToggleByIndexCommand}" CommandParameter="2"/>
|
||
<KeyBinding Key="NumPad3" Command="{Binding ToggleByIndexCommand}" CommandParameter="3"/>
|
||
<KeyBinding Key="NumPad4" Command="{Binding ToggleByIndexCommand}" CommandParameter="4"/>
|
||
<KeyBinding Key="NumPad5" Command="{Binding ToggleByIndexCommand}" CommandParameter="5"/>
|
||
<KeyBinding Key="NumPad6" Command="{Binding ToggleByIndexCommand}" CommandParameter="6"/>
|
||
<KeyBinding Key="NumPad7" Command="{Binding ToggleByIndexCommand}" CommandParameter="7"/>
|
||
<KeyBinding Key="NumPad8" Command="{Binding ToggleByIndexCommand}" CommandParameter="8"/>
|
||
<KeyBinding Key="NumPad9" Command="{Binding ToggleByIndexCommand}" CommandParameter="9"/>
|
||
<KeyBinding Key="D1" Command="{Binding ToggleByIndexCommand}" CommandParameter="1"/>
|
||
<KeyBinding Key="D2" Command="{Binding ToggleByIndexCommand}" CommandParameter="2"/>
|
||
<KeyBinding Key="D3" Command="{Binding ToggleByIndexCommand}" CommandParameter="3"/>
|
||
<KeyBinding Key="D4" Command="{Binding ToggleByIndexCommand}" CommandParameter="4"/>
|
||
<KeyBinding Key="D5" Command="{Binding ToggleByIndexCommand}" CommandParameter="5"/>
|
||
<KeyBinding Key="D6" Command="{Binding ToggleByIndexCommand}" CommandParameter="6"/>
|
||
<KeyBinding Key="D7" Command="{Binding ToggleByIndexCommand}" CommandParameter="7"/>
|
||
<KeyBinding Key="D8" Command="{Binding ToggleByIndexCommand}" CommandParameter="8"/>
|
||
<KeyBinding Key="D9" Command="{Binding ToggleByIndexCommand}" CommandParameter="9"/>
|
||
</Window.InputBindings>
|
||
|
||
<Grid>
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="32"/>
|
||
<RowDefinition Height="40"/>
|
||
<RowDefinition Height="*"/>
|
||
<RowDefinition Height="Auto"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!-- ═════════════════════ HEADER (32px) ═════════════════════ -->
|
||
<Border Grid.Row="0"
|
||
Background="{DynamicResource Wd.Canvas}"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="0,0,0,1">
|
||
<Grid>
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<!-- Brand: Wild Dragon mark + wordmark. Click on the mark opens About.
|
||
Mark is small (20px) and sits as a quality cue — not as
|
||
marketing chrome. -->
|
||
<StackPanel Grid.Column="0"
|
||
Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
Margin="12,0,0,0">
|
||
<Button Click="OnAboutClick"
|
||
Padding="2"
|
||
Background="Transparent"
|
||
BorderThickness="0"
|
||
Cursor="Hand"
|
||
ToolTip="About TeamsISO">
|
||
<Image Source="/Assets/dragon-mark.png"
|
||
Width="20" Height="20"
|
||
RenderOptions.BitmapScalingMode="HighQuality"/>
|
||
</Button>
|
||
<TextBlock Text="TeamsISO"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="13"
|
||
FontWeight="Medium"
|
||
Foreground="{DynamicResource Wd.Text.Primary}"
|
||
VerticalAlignment="Center"
|
||
Margin="8,0,0,0"/>
|
||
</StackPanel>
|
||
|
||
<!-- Right cluster: three icon buttons. ⌘K opens the command
|
||
palette (Ctrl+K shortcut). The theme button cycles
|
||
dark ↔ light (Ctrl+T). The gear opens the settings
|
||
drawer. That's the entire chrome. -->
|
||
<StackPanel Grid.Column="2"
|
||
Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,10,0">
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Click="OnCommandPaletteClick"
|
||
Padding="8,4"
|
||
Margin="0,0,2,0"
|
||
ToolTip="Command palette (Ctrl+K)"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Secondary}"
|
||
Content="⌘K"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Command="{Binding ToggleThemeCommand}"
|
||
Padding="6,4"
|
||
Margin="0,0,2,0"
|
||
ToolTip="Toggle theme (Ctrl+T)">
|
||
<Path Data="M 8,2 C 8,2 4,4 4,8 C 4,12 8,14 8,14 C 5,14 2,11 2,8 C 2,5 5,2 8,2 Z"
|
||
Stroke="{DynamicResource Wd.Text.Secondary}"
|
||
StrokeThickness="1.4"
|
||
Fill="{DynamicResource Wd.Text.Secondary}"
|
||
Width="14" Height="14"
|
||
Stretch="None"/>
|
||
</Button>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Click="OnSettingsToggleClick"
|
||
Padding="6,4"
|
||
ToolTip="Settings">
|
||
<Path Data="M 8,1 L 8,3 M 8,13 L 8,15 M 1,8 L 3,8 M 13,8 L 15,8 M 3,3 L 4.5,4.5 M 11.5,11.5 L 13,13 M 3,13 L 4.5,11.5 M 11.5,4.5 L 13,3 M 8,5.5 C 9.4,5.5 10.5,6.6 10.5,8 C 10.5,9.4 9.4,10.5 8,10.5 C 6.6,10.5 5.5,9.4 5.5,8 C 5.5,6.6 6.6,5.5 8,5.5"
|
||
Stroke="{DynamicResource Wd.Text.Secondary}"
|
||
StrokeThickness="1.4"
|
||
Fill="Transparent"
|
||
Width="14" Height="14"
|
||
Stretch="None"/>
|
||
</Button>
|
||
</StackPanel>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- ═════════════════════ TRANSPORT STRIP (40px) ═════════════════════ -->
|
||
<Border Grid.Row="1"
|
||
Background="{DynamicResource Wd.Canvas}"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="0,0,0,1">
|
||
<Grid Margin="20,0,20,0" VerticalAlignment="Center">
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
<StackPanel Grid.Column="0"
|
||
Orientation="Horizontal"
|
||
VerticalAlignment="Center">
|
||
<!-- Session timer — green dot + elapsed when at least one ISO is live -->
|
||
<StackPanel Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,20,0"
|
||
Visibility="{Binding IsSessionActive, Converter={StaticResource BoolToVis}}">
|
||
<Ellipse Width="7" Height="7"
|
||
Fill="{DynamicResource Wd.Accent.Cyan}"
|
||
VerticalAlignment="Center"/>
|
||
<TextBlock Text="{Binding SessionElapsed}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="12"
|
||
FontWeight="Medium"
|
||
Foreground="{DynamicResource Wd.Text.Primary}"
|
||
VerticalAlignment="Center"
|
||
Margin="8,0,0,0"/>
|
||
</StackPanel>
|
||
|
||
<!-- Participant counts — labels in tracked smallcaps, values in mono.
|
||
The space between value and next label uses a middle dot. -->
|
||
<StackPanel Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,20,0">
|
||
<TextBlock Text="PART"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="10"
|
||
FontWeight="SemiBold"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding ParticipantCount, Mode=OneWay, FallbackValue=0}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="12"
|
||
Foreground="{DynamicResource Wd.Text.Primary}"
|
||
VerticalAlignment="Center"/>
|
||
<TextBlock Text=" · "
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="12"
|
||
Foreground="{DynamicResource Wd.Text.Disabled}"
|
||
VerticalAlignment="Center"/>
|
||
<TextBlock Text="LIVE"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="10"
|
||
FontWeight="SemiBold"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding LiveCount, Mode=OneWay, FallbackValue=0}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="12"
|
||
Foreground="{DynamicResource Wd.Accent.CyanText}"
|
||
VerticalAlignment="Center"/>
|
||
</StackPanel>
|
||
|
||
<!-- Teams meeting pill — only present in-call -->
|
||
<StackPanel Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,20,0"
|
||
Visibility="{Binding IsTeamsInCall, Converter={StaticResource BoolToVis}}">
|
||
<TextBlock Text="CALL"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="10"
|
||
FontWeight="SemiBold"
|
||
Foreground="{DynamicResource Wd.Accent.CyanText}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding TeamsMeetingState}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Secondary}"
|
||
VerticalAlignment="Center"
|
||
MaxWidth="240"
|
||
TextTrimming="CharacterEllipsis"/>
|
||
</StackPanel>
|
||
|
||
</StackPanel>
|
||
|
||
<!-- Control surface — only present when listening, right-aligned -->
|
||
<StackPanel Grid.Column="2"
|
||
Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
Visibility="{Binding IsControlSurfaceRunning, Converter={StaticResource BoolToVis}}">
|
||
<TextBlock Text="CTRL"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="10"
|
||
FontWeight="SemiBold"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,6,0"/>
|
||
<TextBlock Text="{Binding ControlSurfaceText}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Accent.CyanText}"
|
||
VerticalAlignment="Center"/>
|
||
</StackPanel>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- ═════════════════════ BODY ═════════════════════ -->
|
||
<Grid Grid.Row="2">
|
||
<Grid.RowDefinitions>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="Auto"/>
|
||
<RowDefinition Height="*"/>
|
||
</Grid.RowDefinitions>
|
||
|
||
<!-- Alert banner — appears when AlertBanner.IsVisible flips on -->
|
||
<Border Grid.Row="0"
|
||
Background="{DynamicResource Wd.Accent.CoralBg}"
|
||
BorderBrush="{DynamicResource Wd.Accent.Coral}"
|
||
BorderThickness="0,0,0,1"
|
||
Padding="24,10"
|
||
Visibility="{Binding AlertBanner.IsVisible, Converter={StaticResource BoolToVis}}">
|
||
<DockPanel>
|
||
<Button DockPanel.Dock="Right"
|
||
Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Dismiss"
|
||
Command="{Binding AlertBanner.DismissCommand}"
|
||
Margin="12,0,0,0"/>
|
||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||
<Ellipse Width="7" Height="7"
|
||
Fill="{DynamicResource Wd.Accent.Coral}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,10,0"/>
|
||
<TextBlock Text="{Binding AlertBanner.Message}"
|
||
Style="{StaticResource Wd.Text.Body}"
|
||
FontWeight="SemiBold"
|
||
VerticalAlignment="Center"/>
|
||
</StackPanel>
|
||
</DockPanel>
|
||
</Border>
|
||
|
||
<!-- Update banner — Forgejo release available -->
|
||
<Border Grid.Row="1"
|
||
Margin="20,12,20,0"
|
||
Padding="14,10"
|
||
Background="{DynamicResource Wd.Accent.CyanMuted}"
|
||
BorderBrush="{DynamicResource Wd.Accent.Cyan}"
|
||
BorderThickness="1"
|
||
CornerRadius="{StaticResource Radius.M}"
|
||
Visibility="{Binding UpdateBanner.IsVisible, Converter={StaticResource BoolToVis}}">
|
||
<Grid>
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
<Ellipse Grid.Column="0"
|
||
Width="7" Height="7"
|
||
Fill="{DynamicResource Wd.Accent.Cyan}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,12,0"/>
|
||
<TextBlock Grid.Column="1"
|
||
Text="{Binding UpdateBanner.Message}"
|
||
Style="{StaticResource Wd.Text.Body}"
|
||
FontSize="12"
|
||
VerticalAlignment="Center"/>
|
||
<Button Grid.Column="2"
|
||
Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Get update"
|
||
Command="{Binding UpdateBanner.OpenReleasePageCommand}"
|
||
Padding="14,4"
|
||
Margin="0,0,8,0"/>
|
||
<Button Grid.Column="3"
|
||
Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Dismiss"
|
||
Command="{Binding UpdateBanner.DismissCommand}"
|
||
Padding="14,4"/>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- Action toolbar — primary verbs above the participants table -->
|
||
<Border Grid.Row="2"
|
||
Padding="20,14,20,12">
|
||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||
<Button Style="{StaticResource Wd.Button.Primary}"
|
||
Command="{Binding EnableAllOnlineCommand}"
|
||
Content="Enable all"
|
||
Padding="14,7"
|
||
Margin="0,0,8,0"
|
||
ToolTip="Enable ISO routing for every online participant"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Command="{Binding RefreshDiscoveryCommand}"
|
||
Content="Refresh"
|
||
Padding="14,7"
|
||
Margin="0,0,8,0"
|
||
ToolTip="Refresh NDI discovery (Ctrl+R)"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Click="OnPresetsClick"
|
||
Content="Presets"
|
||
Padding="14,7"
|
||
Margin="0,0,8,0"
|
||
ToolTip="Open operator presets"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Command="{Binding StopAllIsosCommand}"
|
||
Content="Stop all"
|
||
Padding="14,7"
|
||
ToolTip="Disable every running ISO (Ctrl+Shift+S)"/>
|
||
|
||
<!-- Teams launch / hide — small icon buttons, after a separator -->
|
||
<Border Width="1"
|
||
Background="{DynamicResource Wd.Border}"
|
||
Margin="14,4,14,4"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Click="OnLaunchTeamsClick"
|
||
MouseRightButtonUp="OnLaunchTeamsRightClick"
|
||
Padding="10,7"
|
||
Margin="0,0,4,0"
|
||
ToolTip="Launch Microsoft Teams (right-click to stop)">
|
||
<Path Data="M 4,8 L 16,8 L 16,16 L 4,16 Z M 16,11 L 22,8 L 22,16 L 16,13 Z"
|
||
Stroke="{DynamicResource Wd.Text.Secondary}"
|
||
StrokeThickness="1.5"
|
||
Fill="Transparent"
|
||
StrokeLineJoin="Round"
|
||
Width="18" Height="14"
|
||
Stretch="Uniform"/>
|
||
</Button>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Click="OnToggleTeamsWindowClick"
|
||
Padding="10,7"
|
||
ToolTip="Hide / show Teams windows">
|
||
<Path Data="M 1,11 C 5,4 17,4 21,11 C 17,18 5,18 1,11 Z M 11,8 A 3,3 0 1 1 11,14 A 3,3 0 1 1 11,8 Z"
|
||
Stroke="{DynamicResource Wd.Text.Secondary}"
|
||
StrokeThickness="1.4"
|
||
Fill="Transparent"
|
||
Width="18" Height="14"
|
||
Stretch="Uniform"/>
|
||
</Button>
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!--
|
||
Participants table — v2 "Studio Terminal" layout.
|
||
|
||
Five columns:
|
||
1. State LED 24px — 8×8 hard-edged square. Filled cyan
|
||
when LIVE; filled coral on ERROR;
|
||
filled amber on NO SIGNAL / STARTING;
|
||
hollow neutral when OFF.
|
||
2. Name + caption * — DisplayName (Inter 13/Medium) plus
|
||
source machine + state label below
|
||
in JetBrains Mono 11/Tertiary.
|
||
3. Audio meter 110px — five vertical hard-edged bars,
|
||
each lit when DisplayedAudioLevel
|
||
crosses its threshold (0.2, 0.4,
|
||
0.6, 0.8, 1.0). No averaging.
|
||
4. Output name 150px — JetBrains Mono 12 — the NDI source
|
||
name TeamsISO broadcasts as.
|
||
5. ISO toggle pill 110px — LIVE = cyan-muted fill with cyan
|
||
text; OFF = hollow neutral; ERROR
|
||
gets the existing trigger swap.
|
||
|
||
Row height 52 (down from 56). Active speaker = full-row
|
||
bg.active-speaker tint set by the global DataGridRow style
|
||
(avoids the impeccable side-stripe-border ban).
|
||
-->
|
||
<Border Grid.Row="3"
|
||
Margin="20,0,20,12"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="1"
|
||
CornerRadius="{StaticResource Radius.M}"
|
||
Background="{DynamicResource Wd.Surface}">
|
||
<DataGrid x:Name="ParticipantsGrid"
|
||
ItemsSource="{Binding ParticipantsView}"
|
||
AutoGenerateColumns="False"
|
||
HeadersVisibility="Column"
|
||
GridLinesVisibility="None"
|
||
RowBackground="Transparent"
|
||
AlternatingRowBackground="Transparent"
|
||
BorderThickness="0"
|
||
CanUserAddRows="False"
|
||
CanUserDeleteRows="False"
|
||
CanUserResizeRows="False"
|
||
SelectionMode="Single"
|
||
SelectionUnit="FullRow"
|
||
RowHeight="52">
|
||
<DataGrid.Columns>
|
||
<!-- Col 1 — State LED. 8×8 hard-edged Rectangle.
|
||
Default fill is hollow (transparent with stroke). DataTriggers
|
||
swap the fill based on StateLabel: LIVE → cyan filled,
|
||
NO SIGNAL / STARTING → amber filled, ERROR → coral filled.
|
||
No rounding — broadcast vocabulary uses sharp LEDs. -->
|
||
<DataGridTemplateColumn Header="" Width="24" IsReadOnly="True">
|
||
<DataGridTemplateColumn.CellTemplate>
|
||
<DataTemplate>
|
||
<Rectangle Width="8" Height="8"
|
||
HorizontalAlignment="Center"
|
||
VerticalAlignment="Center"
|
||
StrokeThickness="1.5">
|
||
<Rectangle.Style>
|
||
<Style TargetType="Rectangle">
|
||
<Setter Property="Fill" Value="Transparent"/>
|
||
<Setter Property="Stroke" Value="{DynamicResource Wd.BorderStrong}"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding StateLabel}" Value="LIVE">
|
||
<Setter Property="Fill" Value="{DynamicResource Wd.Accent.Cyan}"/>
|
||
<Setter Property="Stroke" Value="{DynamicResource Wd.Accent.Cyan}"/>
|
||
</DataTrigger>
|
||
<DataTrigger Binding="{Binding StateLabel}" Value="ERROR">
|
||
<Setter Property="Fill" Value="{DynamicResource Wd.Accent.Coral}"/>
|
||
<Setter Property="Stroke" Value="{DynamicResource Wd.Accent.Coral}"/>
|
||
</DataTrigger>
|
||
<DataTrigger Binding="{Binding StateLabel}" Value="NO SIGNAL">
|
||
<Setter Property="Fill" Value="{DynamicResource Wd.Status.Warn}"/>
|
||
<Setter Property="Stroke" Value="{DynamicResource Wd.Status.Warn}"/>
|
||
</DataTrigger>
|
||
<DataTrigger Binding="{Binding StateLabel}" Value="STARTING">
|
||
<Setter Property="Fill" Value="{DynamicResource Wd.Status.Warn}"/>
|
||
<Setter Property="Stroke" Value="{DynamicResource Wd.Status.Warn}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Rectangle.Style>
|
||
</Rectangle>
|
||
</DataTemplate>
|
||
</DataGridTemplateColumn.CellTemplate>
|
||
</DataGridTemplateColumn>
|
||
|
||
<!-- Col 2 — Name + caption. Display name (Inter 13/Medium) above,
|
||
source machine + state caption (Mono 11/Tertiary) below. -->
|
||
<DataGridTemplateColumn Header="Participant" Width="*" IsReadOnly="True">
|
||
<DataGridTemplateColumn.CellTemplate>
|
||
<DataTemplate>
|
||
<StackPanel VerticalAlignment="Center">
|
||
<TextBlock Text="{Binding DisplayName}"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="13"
|
||
FontWeight="Medium"
|
||
Foreground="{DynamicResource Wd.Text.Primary}"
|
||
TextTrimming="CharacterEllipsis"/>
|
||
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
|
||
<TextBlock Text="{Binding SourceMachine}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
TextTrimming="CharacterEllipsis"
|
||
MaxWidth="180"/>
|
||
<TextBlock Text=" · "
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Disabled}"/>
|
||
<TextBlock Text="{Binding StateLabel}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"/>
|
||
</StackPanel>
|
||
</StackPanel>
|
||
</DataTemplate>
|
||
</DataGridTemplateColumn.CellTemplate>
|
||
</DataGridTemplateColumn>
|
||
|
||
<!-- Col 3 — Audio meter. 5 vertical bars; each lit when
|
||
DisplayedAudioLevel crosses its threshold. -->
|
||
<DataGridTemplateColumn Header="Audio" Width="110" IsReadOnly="True">
|
||
<DataGridTemplateColumn.CellTemplate>
|
||
<DataTemplate>
|
||
<StackPanel Orientation="Horizontal"
|
||
VerticalAlignment="Center"
|
||
HorizontalAlignment="Left">
|
||
<Rectangle Width="6" Height="6"
|
||
Margin="0,0,3,0"
|
||
Fill="{DynamicResource Wd.Accent.Cyan}"
|
||
Opacity="{Binding DisplayedAudioLevel, Converter={StaticResource LevelGate}, ConverterParameter=0.2}"
|
||
VerticalAlignment="Bottom"/>
|
||
<Rectangle Width="6" Height="10"
|
||
Margin="0,0,3,0"
|
||
Fill="{DynamicResource Wd.Accent.Cyan}"
|
||
Opacity="{Binding DisplayedAudioLevel, Converter={StaticResource LevelGate}, ConverterParameter=0.4}"
|
||
VerticalAlignment="Bottom"/>
|
||
<Rectangle Width="6" Height="14"
|
||
Margin="0,0,3,0"
|
||
Fill="{DynamicResource Wd.Accent.Cyan}"
|
||
Opacity="{Binding DisplayedAudioLevel, Converter={StaticResource LevelGate}, ConverterParameter=0.6}"
|
||
VerticalAlignment="Bottom"/>
|
||
<Rectangle Width="6" Height="18"
|
||
Margin="0,0,3,0"
|
||
Fill="{DynamicResource Wd.Status.Warn}"
|
||
Opacity="{Binding DisplayedAudioLevel, Converter={StaticResource LevelGate}, ConverterParameter=0.8}"
|
||
VerticalAlignment="Bottom"/>
|
||
<Rectangle Width="6" Height="22"
|
||
Fill="{DynamicResource Wd.Accent.Coral}"
|
||
Opacity="{Binding DisplayedAudioLevel, Converter={StaticResource LevelGate}, ConverterParameter=0.95}"
|
||
VerticalAlignment="Bottom"/>
|
||
</StackPanel>
|
||
</DataTemplate>
|
||
</DataGridTemplateColumn.CellTemplate>
|
||
</DataGridTemplateColumn>
|
||
|
||
<!-- Col 4 — Output name (mono). The NDI source name TeamsISO
|
||
will broadcast this participant as. -->
|
||
<DataGridTemplateColumn Header="Output" Width="150" IsReadOnly="True">
|
||
<DataGridTemplateColumn.CellTemplate>
|
||
<DataTemplate>
|
||
<TextBlock Text="{Binding OutputName}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="12"
|
||
Foreground="{DynamicResource Wd.Text.Secondary}"
|
||
VerticalAlignment="Center"
|
||
TextTrimming="CharacterEllipsis"/>
|
||
</DataTemplate>
|
||
</DataGridTemplateColumn.CellTemplate>
|
||
</DataGridTemplateColumn>
|
||
|
||
<!-- Col 5 — ISO toggle pill. LIVE = cyan-muted fill + cyan border + cyan text.
|
||
OFF = hollow neutral. Error states use the existing IsoToggle style. -->
|
||
<DataGridTemplateColumn Header="ISO" Width="110">
|
||
<DataGridTemplateColumn.CellTemplate>
|
||
<DataTemplate>
|
||
<Button Command="{Binding ToggleIsoCommand}"
|
||
Margin="0,0,12,0"
|
||
Padding="14,6"
|
||
VerticalAlignment="Center">
|
||
<Button.Style>
|
||
<Style TargetType="Button" BasedOn="{StaticResource Wd.Button.IsoToggle}">
|
||
<Setter Property="Content" Value="Enable"/>
|
||
<Style.Triggers>
|
||
<DataTrigger Binding="{Binding IsEnabled}" Value="True">
|
||
<Setter Property="Content" Value="● LIVE"/>
|
||
<Setter Property="Background" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
|
||
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
|
||
<Setter Property="Foreground" Value="{DynamicResource Wd.Accent.CyanText}"/>
|
||
</DataTrigger>
|
||
</Style.Triggers>
|
||
</Style>
|
||
</Button.Style>
|
||
</Button>
|
||
</DataTemplate>
|
||
</DataGridTemplateColumn.CellTemplate>
|
||
</DataGridTemplateColumn>
|
||
</DataGrid.Columns>
|
||
</DataGrid>
|
||
</Border>
|
||
</Grid>
|
||
|
||
<!-- ═════════════════════ MEETING BAR (conditional) ═════════════════════ -->
|
||
<Border Grid.Row="3"
|
||
Background="{DynamicResource Wd.SurfaceElevated}"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="0,1,0,0"
|
||
Padding="20,10,20,10"
|
||
Visibility="{Binding IsTeamsInCall, Converter={StaticResource BoolToVis}}">
|
||
<Grid>
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="Auto"/>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
|
||
<StackPanel Grid.Column="0"
|
||
Orientation="Horizontal"
|
||
VerticalAlignment="Center">
|
||
<TextBlock Text="IN CALL"
|
||
FontFamily="{StaticResource Wd.Font.Sans}"
|
||
FontSize="10"
|
||
FontWeight="SemiBold"
|
||
Foreground="{DynamicResource Wd.Accent.CyanText}"
|
||
VerticalAlignment="Center"
|
||
Margin="0,0,10,0"/>
|
||
<TextBlock Text="{Binding TeamsMeetingState}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="12"
|
||
Foreground="{DynamicResource Wd.Text.Primary}"
|
||
VerticalAlignment="Center"
|
||
MaxWidth="500"
|
||
TextTrimming="CharacterEllipsis"/>
|
||
</StackPanel>
|
||
|
||
<!-- Quick-join field — paste a meeting URL, click Join -->
|
||
<StackPanel Grid.Column="1"
|
||
Orientation="Horizontal"
|
||
HorizontalAlignment="Center"
|
||
VerticalAlignment="Center"
|
||
Visibility="{Binding IsTeamsInCall, Converter={StaticResource BoolToVisInverse}}">
|
||
<!-- Hidden when in call to keep the bar uncluttered -->
|
||
</StackPanel>
|
||
|
||
<StackPanel Grid.Column="2"
|
||
Orientation="Horizontal"
|
||
VerticalAlignment="Center">
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Command="{Binding ToggleMuteCommand}"
|
||
Content="Mute"
|
||
Padding="14,6"
|
||
Margin="0,0,6,0"
|
||
MinWidth="64"
|
||
ToolTip="Toggle microphone mute in Teams"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Command="{Binding ToggleCameraCommand}"
|
||
Content="Cam"
|
||
Padding="14,6"
|
||
Margin="0,0,6,0"
|
||
MinWidth="64"
|
||
ToolTip="Toggle camera in Teams"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Command="{Binding LeaveCallCommand}"
|
||
Content="Leave"
|
||
Padding="14,6"
|
||
MinWidth="64"
|
||
Foreground="{DynamicResource Wd.Accent.Coral}"
|
||
BorderBrush="{DynamicResource Wd.Accent.Coral}"
|
||
ToolTip="Leave the Teams call"/>
|
||
</StackPanel>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- ═════════════════════ SETTINGS DRAWER (overlay) ═════════════════════
|
||
Slides in over the main content from the right when the header gear
|
||
is clicked. Backdrop scrim is a semi-transparent overlay over the
|
||
whole window; clicking it dismisses the drawer. Esc also dismisses
|
||
(handled in code-behind). The drawer carries the same settings
|
||
surface as v1 — OUTPUT / NETWORK / DISPLAY tabs with the existing
|
||
bindings — so the engine wiring is preserved through the shell
|
||
rebuild. -->
|
||
<Grid Grid.Row="0"
|
||
Grid.RowSpan="4"
|
||
x:Name="SettingsDrawerOverlay"
|
||
Visibility="Collapsed">
|
||
<!-- Scrim — click to dismiss -->
|
||
<Border Background="#80000000"
|
||
MouseLeftButtonDown="OnSettingsScrimClick"/>
|
||
<!-- Drawer panel -->
|
||
<Border HorizontalAlignment="Right"
|
||
Width="420"
|
||
Background="{DynamicResource Wd.Surface}"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="1,0,0,0">
|
||
<DockPanel LastChildFill="True">
|
||
<!-- Drawer header -->
|
||
<Border DockPanel.Dock="Top"
|
||
Padding="20,18,16,16"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="0,0,0,1">
|
||
<Grid>
|
||
<Grid.ColumnDefinitions>
|
||
<ColumnDefinition Width="*"/>
|
||
<ColumnDefinition Width="Auto"/>
|
||
</Grid.ColumnDefinitions>
|
||
<StackPanel Grid.Column="0">
|
||
<TextBlock Text="Settings"
|
||
Style="{StaticResource Wd.Text.Title}"
|
||
FontSize="18"/>
|
||
<TextBlock Text="Per-session global processing"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
Margin="0,2,0,0"/>
|
||
</StackPanel>
|
||
<Button Grid.Column="1"
|
||
Style="{StaticResource Wd.Button.Ghost}"
|
||
Click="OnSettingsToggleClick"
|
||
Padding="8,4"
|
||
ToolTip="Close (Esc)">
|
||
<Path Data="M 0,0 L 10,10 M 10,0 L 0,10"
|
||
Stroke="{DynamicResource Wd.Text.Secondary}"
|
||
StrokeThickness="1.4"
|
||
Width="10" Height="10"
|
||
Stretch="None"/>
|
||
</Button>
|
||
</Grid>
|
||
</Border>
|
||
|
||
<!-- Drawer footer (Apply) -->
|
||
<Border DockPanel.Dock="Bottom"
|
||
Padding="20,12,20,16"
|
||
BorderBrush="{DynamicResource Wd.Border}"
|
||
BorderThickness="0,1,0,0">
|
||
<StackPanel Orientation="Horizontal"
|
||
HorizontalAlignment="Right">
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Close"
|
||
Click="OnSettingsToggleClick"
|
||
Padding="14,6"
|
||
Margin="0,0,8,0"/>
|
||
<Button Style="{StaticResource Wd.Button.Primary}"
|
||
Content="Apply changes"
|
||
Command="{Binding Settings.ApplyCommand}"
|
||
Padding="14,6"/>
|
||
</StackPanel>
|
||
</Border>
|
||
|
||
<!-- Drawer scrollable body — three tabs -->
|
||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||
HorizontalScrollBarVisibility="Disabled">
|
||
<Border Padding="20,16,20,16">
|
||
<TabControl Style="{StaticResource Wd.TabControl}">
|
||
<!-- ─────── OUTPUT ─────── -->
|
||
<TabItem Header="OUTPUT" Style="{StaticResource Wd.TabItem}">
|
||
<StackPanel>
|
||
<TextBlock Text="Target framerate"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,0,0,4"/>
|
||
<ComboBox ItemsSource="{Binding Settings.AvailableFramerates}"
|
||
SelectedItem="{Binding Settings.Framerate}">
|
||
<ComboBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<TextBlock Text="{Binding Converter={StaticResource EnumDesc}}"/>
|
||
</DataTemplate>
|
||
</ComboBox.ItemTemplate>
|
||
</ComboBox>
|
||
|
||
<TextBlock Text="Target resolution"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,12,0,4"/>
|
||
<ComboBox ItemsSource="{Binding Settings.AvailableResolutions}"
|
||
SelectedItem="{Binding Settings.Resolution}">
|
||
<ComboBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<TextBlock Text="{Binding Converter={StaticResource EnumDesc}}"/>
|
||
</DataTemplate>
|
||
</ComboBox.ItemTemplate>
|
||
</ComboBox>
|
||
|
||
<TextBlock Text="Aspect mode"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,12,0,4"/>
|
||
<ComboBox ItemsSource="{Binding Settings.AvailableAspectModes}"
|
||
SelectedItem="{Binding Settings.Aspect}">
|
||
<ComboBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<TextBlock Text="{Binding Converter={StaticResource EnumDesc}}"/>
|
||
</DataTemplate>
|
||
</ComboBox.ItemTemplate>
|
||
</ComboBox>
|
||
|
||
<TextBlock Text="Audio mode"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,12,0,4"/>
|
||
<ComboBox ItemsSource="{Binding Settings.AvailableAudioModes}"
|
||
SelectedItem="{Binding Settings.Audio}">
|
||
<ComboBox.ItemTemplate>
|
||
<DataTemplate>
|
||
<TextBlock Text="{Binding Converter={StaticResource EnumDesc}}"/>
|
||
</DataTemplate>
|
||
</ComboBox.ItemTemplate>
|
||
</ComboBox>
|
||
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Reset to defaults"
|
||
Command="{Binding Settings.ResetOutputDefaultsCommand}"
|
||
HorizontalAlignment="Stretch"
|
||
Margin="0,16,0,0"
|
||
Padding="0,8"/>
|
||
</StackPanel>
|
||
</TabItem>
|
||
|
||
<!-- ─────── NETWORK ─────── -->
|
||
<TabItem Header="NETWORK" Style="{StaticResource Wd.TabItem}">
|
||
<StackPanel>
|
||
<TextBlock Text="Discovery group"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,0,0,4"/>
|
||
<TextBox Text="{Binding Settings.DiscoveryGroups, UpdateSourceTrigger=PropertyChanged}"/>
|
||
|
||
<TextBlock Text="Output group"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,12,0,4"/>
|
||
<TextBox Text="{Binding Settings.OutputGroups, UpdateSourceTrigger=PropertyChanged}"/>
|
||
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Apply transcoder topology"
|
||
Command="{Binding Settings.ApplyTranscoderTopologyCommand}"
|
||
HorizontalAlignment="Stretch"
|
||
Margin="0,16,0,0"
|
||
Padding="0,9"/>
|
||
<TextBlock Text="Pins Teams' raw NDI broadcasts to a private 'teamsiso-input' group so they don't pollute the Public network. Restart Teams after applying."
|
||
Style="{StaticResource Wd.Text.Body}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
TextWrapping="Wrap"
|
||
Margin="0,6,0,0"/>
|
||
|
||
<TextBlock Text="Output name template"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,16,0,4"/>
|
||
<TextBox Text="{Binding Settings.OutputNameTemplate, UpdateSourceTrigger=LostFocus}"
|
||
FontFamily="{StaticResource Wd.Font.Mono}"
|
||
FontSize="11"/>
|
||
<TextBlock Text="Tokens: {name}, {guid}, {machine}, {timestamp}. Default: TEAMSISO_{guid}."
|
||
Style="{StaticResource Wd.Text.Body}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Text.Tertiary}"
|
||
TextWrapping="Wrap"
|
||
Margin="0,4,0,0"/>
|
||
</StackPanel>
|
||
</TabItem>
|
||
|
||
<!-- ─────── APP ─────── -->
|
||
<TabItem Header="APP" Style="{StaticResource Wd.TabItem}">
|
||
<StackPanel>
|
||
<CheckBox Content="Hide my self-preview from participants"
|
||
IsChecked="{Binding Settings.HideLocalSelf}"/>
|
||
<CheckBox Content="Auto-disable ISOs when a participant leaves"
|
||
IsChecked="{Binding Settings.AutoDisableOnDeparture}"
|
||
Margin="0,8,0,0"/>
|
||
<CheckBox Content="Auto-apply last preset on launch"
|
||
IsChecked="{Binding Settings.AutoApplyLastPreset}"
|
||
Margin="0,8,0,0"/>
|
||
|
||
<TextBlock Text="Sort participants by"
|
||
Style="{StaticResource Wd.Text.Subtle}"
|
||
Margin="0,14,0,4"/>
|
||
<ComboBox ItemsSource="{Binding Settings.AvailableSortModes}"
|
||
SelectedItem="{Binding Settings.ParticipantSort}"/>
|
||
|
||
<CheckBox Content="Minimize to system tray"
|
||
IsChecked="{Binding Settings.MinimizeToTray}"
|
||
Margin="0,14,0,0"/>
|
||
|
||
<Border Margin="0,16,0,8"
|
||
Height="1"
|
||
Background="{DynamicResource Wd.Border}"/>
|
||
|
||
<CheckBox Content="Launch Microsoft Teams on TeamsISO startup"
|
||
IsChecked="{Binding Settings.LaunchTeamsOnStartup}"/>
|
||
<CheckBox Content="Auto-hide Teams windows when launched"
|
||
IsChecked="{Binding Settings.AutoHideTeamsWindows}"
|
||
Margin="0,8,0,0"/>
|
||
|
||
<Border Margin="0,16,0,8"
|
||
Height="1"
|
||
Background="{DynamicResource Wd.Border}"/>
|
||
|
||
<CheckBox Content="Embed Teams window (experimental)"
|
||
IsChecked="{Binding Settings.EmbedTeamsWindow}"/>
|
||
<Button Style="{StaticResource Wd.Button.Ghost}"
|
||
Content="Open embed window"
|
||
Click="OnOpenEmbedWindowClick"
|
||
HorizontalAlignment="Stretch"
|
||
Margin="0,8,0,0"
|
||
Padding="0,8"
|
||
IsEnabled="{Binding Settings.EmbedTeamsWindow}"/>
|
||
|
||
<Border Margin="0,16,0,8"
|
||
Height="1"
|
||
Background="{DynamicResource Wd.Border}"/>
|
||
|
||
<CheckBox Content="Control surface (Stream Deck / Companion / web)"
|
||
IsChecked="{Binding Settings.ControlSurfaceEnabled}"/>
|
||
<CheckBox Content="LAN-reachable"
|
||
IsChecked="{Binding Settings.ControlSurfaceLanReachable}"
|
||
Margin="20,4,0,0"/>
|
||
<TextBlock Text="{Binding Settings.ControlSurfaceUrl}"
|
||
Style="{StaticResource Wd.Text.Mono}"
|
||
FontSize="11"
|
||
Foreground="{DynamicResource Wd.Accent.CyanText}"
|
||
Margin="20,4,0,0"/>
|
||
</StackPanel>
|
||
</TabItem>
|
||
</TabControl>
|
||
</Border>
|
||
</ScrollViewer>
|
||
</DockPanel>
|
||
</Border>
|
||
</Grid>
|
||
</Grid>
|
||
</Window>
|