Unit 4 of the sound-bar refactor. `Controls/AudioDock` takes the bottom row that held the empty `BottomBar` spacer (deleted): four bay containers (MIC / GAME / TRAX / LIP-SYNC) above a 36px master strip, all token-styled. Height comes from `Models/AudioDockLayout`, not from a setting: 168px normally, 36px below a 900px window height. At the 1366×768 minimum a full dock leaves ~398px for the preview, so the collapse is mandatory, not cosmetic. The dock listens to its window's SizeChanged and re-applies. Nothing here pretends to be a meter yet — the bays and the master readouts fill in over the next units, each with its own test. Guard: AudioDockLayoutTests pins both sides of the threshold (768 collapsed, 1040 expanded), the boundary itself, and the two heights as the design's numbers.
162 lines
8.6 KiB
XML
162 lines
8.6 KiB
XML
<Window x:Class="ytLive.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:ytLive.ViewModels"
|
|
xmlns:models="clr-namespace:ytLive.Models"
|
|
xmlns:Helpers="clr-namespace:ytLive.Helpers"
|
|
xmlns:controls="clr-namespace:ytLive.Controls"
|
|
xmlns:notifications="clr-namespace:Notification.Wpf.Controls;assembly=Notification.Wpf"
|
|
mc:Ignorable="d"
|
|
Title="{Binding WindowTitle}" Height="1040" Width="1920"
|
|
MinWidth="1366" MinHeight="768"
|
|
Icon="/ytLive;component/Assets/llamacasty-icon.png"
|
|
Background="{StaticResource Brush.Background}"
|
|
FontFamily="{StaticResource FontFamily.Sans}"
|
|
WindowStartupLocation="Manual"
|
|
Closing="MainWindow_Closing"
|
|
Loaded="MainWindow_Loaded"
|
|
Activated="MainWindow_Activated"
|
|
Deactivated="MainWindow_Deactivated"
|
|
PreviewMouseLeftButtonDown="Window_PreviewMouseLeftButtonDown"
|
|
ContextMenuOpening="Window_ContextMenuOpening">
|
|
|
|
<Window.DataContext>
|
|
<vm:MainViewModel/>
|
|
</Window.DataContext>
|
|
|
|
<Window.TaskbarItemInfo>
|
|
<TaskbarItemInfo x:Name="TaskbarInfo"/>
|
|
</Window.TaskbarItemInfo>
|
|
|
|
<Window.Resources>
|
|
<ResourceDictionary>
|
|
<Helpers:DroppedFramesToBrushConverter x:Key="DroppedToBrush"/>
|
|
<Helpers:DroppedPercentConverter x:Key="DroppedPercent"/>
|
|
|
|
<!-- Red dot shown in the taskbar icon while live -->
|
|
<DrawingImage x:Key="LiveOverlay">
|
|
<DrawingImage.Drawing>
|
|
<DrawingGroup>
|
|
<GeometryDrawing Brush="{StaticResource Brush.Tertiary}">
|
|
<GeometryDrawing.Geometry>
|
|
<EllipseGeometry Center="8,8" RadiusX="8" RadiusY="8"/>
|
|
</GeometryDrawing.Geometry>
|
|
</GeometryDrawing>
|
|
</DrawingGroup>
|
|
</DrawingImage.Drawing>
|
|
</DrawingImage>
|
|
|
|
<!-- EyeButton/EyeIconStyle MOVED to Themes/Controls.xaml (2026-09-01): Controls/
|
|
LeftPanel.xaml consumes them via StaticResource, and window-scope resources
|
|
are invisible to a UserControl at parse time — the "known test failure" that
|
|
was actually an app-crash regression from the LeftPanel extraction. -->
|
|
</ResourceDictionary>
|
|
</Window.Resources>
|
|
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
<RowDefinition Height="Auto"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- ═══ TOP BAR: Stream Controls ═══ -->
|
|
<Border Grid.Row="0" Background="{Binding TopBarBackground}" Padding="16,10">
|
|
<controls:TopBar x:Name="TopBar"/>
|
|
</Border>
|
|
|
|
<!-- ═══ MIDDLE: Main Content ═══ -->
|
|
<controls:HealthBanner Grid.Row="1"/>
|
|
|
|
<Grid Grid.Row="2" Margin="8">
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="360"/>
|
|
<ColumnDefinition Width="3*"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<!-- STREAM READOUTS (top-left cell, above the layers) + resolution -->
|
|
<Border Grid.Row="0" Grid.Column="0" Background="{StaticResource Brush.SurfaceContainerLowest}" CornerRadius="4" Padding="10,8" Margin="0,0,8,0">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<TextBlock Grid.Row="0" Grid.Column="0" Text="Bitrate" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="12" Margin="0,0,12,2"/>
|
|
<TextBlock Grid.Row="0" Grid.Column="1" Foreground="{StaticResource Brush.OnSurface}" FontSize="13" FontFamily="{StaticResource FontFamily.Mono}" HorizontalAlignment="Right" Margin="0,0,0,2">
|
|
<Run Text="{Binding CurrentHealth.CurrentBitrate, Mode=OneWay, StringFormat={}{0:0.0}}"/><Run Text=" Mbps"/>
|
|
</TextBlock>
|
|
|
|
<TextBlock Grid.Row="1" Grid.Column="0" Text="FPS" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="12" Margin="0,0,12,2"/>
|
|
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding CurrentHealth.FPS, Mode=OneWay, StringFormat={}{0:0}}"
|
|
Foreground="{StaticResource Brush.OnSurface}" FontSize="13" FontFamily="{StaticResource FontFamily.Mono}" HorizontalAlignment="Right" Margin="0,0,0,2"/>
|
|
|
|
<TextBlock Grid.Row="2" Grid.Column="0" Text="Dropped" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="12" Margin="0,0,12,2"/>
|
|
<TextBlock Grid.Row="2" Grid.Column="1" FontSize="13" FontFamily="{StaticResource FontFamily.Mono}" HorizontalAlignment="Right" Margin="0,0,0,2"
|
|
Foreground="{Binding CurrentHealth.DroppedFrames, Converter={StaticResource DroppedToBrush}}">
|
|
<TextBlock.Text>
|
|
<MultiBinding Converter="{StaticResource DroppedPercent}">
|
|
<Binding Path="CurrentHealth.DroppedFrames" Mode="OneWay"/>
|
|
<Binding Path="CurrentHealth.FPS" Mode="OneWay"/>
|
|
<Binding Path="CurrentHealth.StreamDuration" Mode="OneWay"/>
|
|
</MultiBinding>
|
|
</TextBlock.Text>
|
|
</TextBlock>
|
|
|
|
<TextBlock Grid.Row="3" Grid.Column="0" Text="Live:" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="12" Margin="0,0,12,2"/>
|
|
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding CurrentHealth.StreamDuration, Mode=OneWay, StringFormat={}{0:hh\:mm\:ss}}"
|
|
Foreground="{StaticResource Brush.Attention}" FontSize="13" FontFamily="{StaticResource FontFamily.Mono}" FontWeight="SemiBold" HorizontalAlignment="Right" Margin="0,0,0,2"/>
|
|
|
|
<TextBlock Grid.Row="4" Grid.ColumnSpan="2" Text="{Binding CurrentHealth.HealthMessage}"
|
|
Foreground="{StaticResource Brush.Attention}" FontSize="12" TextWrapping="Wrap" Margin="0,0,0,6"/>
|
|
|
|
<ComboBox Grid.Row="5" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Style="{StaticResource YtComboBox}"
|
|
ItemsSource="{Binding QualityOptions}"
|
|
SelectedItem="{Binding SelectedQuality}"
|
|
DisplayMemberPath="Label"
|
|
ToolTip="{Binding ResolutionHelp}"
|
|
IsEnabled="{Binding IsOffline}"/>
|
|
</Grid>
|
|
</Border>
|
|
|
|
<!-- ═══ THUMBNAIL STRIP (over the preview column; left column stays empty) ═══ -->
|
|
<controls:SceneThumbnailStrip x:Name="SceneStrip" Grid.Row="0" Grid.Column="1" Margin="8,0" Height="154"/>
|
|
|
|
<!-- LEFT PANEL: one panel, two states.
|
|
Offline (edit mode): LAYERS + PROPERTIES
|
|
Live/Recording: YouTube Live Chat -->
|
|
<controls:LeftPanel x:Name="LeftPanel" Grid.Row="1" Grid.Column="0"/>
|
|
|
|
|
|
<!-- CENTER: Preview Area -->
|
|
<controls:PreviewPane x:Name="PreviewPane" Grid.Row="1" Grid.Column="1"/>
|
|
</Grid>
|
|
|
|
|
|
<controls:AudioDock Grid.Row="3"/>
|
|
<!-- ═══ OVERLAY: Settings / Bug / Feature / About ═══ -->
|
|
<controls:OverlayHost Grid.RowSpan="3"/>
|
|
|
|
<!-- ═══ TOASTS: non-blocking notifications (bottom-right, above footer) ═══ -->
|
|
<notifications:NotificationArea x:Name="ToastArea"
|
|
Grid.RowSpan="4"
|
|
Position="BottomRight" MaxItems="4"
|
|
Margin="0,0,12,96"/>
|
|
</Grid>
|
|
</Window>
|