Audio UX (UI) + bottom bar rework: two-line footer (dropped/duration under bitrate/fps), centered sound meter (blank→green→yellow→red, zone markers at 60%/80%) + MIC chip (MicVolume slider, ToggleMicMuteCommand) — the mic is the creator's only audio control, desktop/game audio is automatic (KISS rule); scenes list is content-height (no dead space before SOURCES); top bar shows the connected YT account avatar/name via SyncConnectedAccount; docs updated (65 tests passing)
This commit is contained in:
+104
-53
@@ -105,6 +105,12 @@
|
||||
|
||||
<!-- Single three-state action button -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="26" Height="26" CornerRadius="13" Background="#16213e" ClipToBounds="True"
|
||||
Margin="0,0,8,0" VerticalAlignment="Center"
|
||||
ToolTip="{Binding AccountDisplayName}"
|
||||
Visibility="{Binding IsConnected, Converter={StaticResource BoolToVis}}">
|
||||
<Image Source="{Binding AccountAvatarUrl}" Stretch="UniformToFill"/>
|
||||
</Border>
|
||||
<Button Content="Start Stream" Style="{StaticResource YtButton}"
|
||||
Command="{Binding StartStreamCommand}"
|
||||
Visibility="{Binding ShowStartStream, Converter={StaticResource BoolToVis}}"/>
|
||||
@@ -128,9 +134,9 @@
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="180"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Scenes: the app has five canonical scenes. Work with less,
|
||||
@@ -244,7 +250,7 @@
|
||||
</Helpers:FocusPreservingListBox>
|
||||
|
||||
<!-- Sources (for active scene) -->
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,12,0,0">
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<TextBlock Text="SOURCES" Style="{StaticResource SectionHeader}" VerticalAlignment="Center"/>
|
||||
<Button ToolTip="Add Source" Style="{StaticResource IconButton}" Margin="4,-4,0,0"
|
||||
Click="AddSourceButton_Click">
|
||||
@@ -739,64 +745,109 @@
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- ═══ BOTTOM BAR: Stream Health ═══ -->
|
||||
<!-- ═══ BOTTOM BAR: Stream Health + Audio ═══ -->
|
||||
<Border Grid.Row="2" Background="#0f3460" Padding="16,6">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="Bitrate:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Style="{StaticResource YtLabel}"
|
||||
Foreground="White" Margin="0,0,20,0">
|
||||
<Run Text="{Binding CurrentHealth.CurrentBitrate, Mode=OneWay}"/>
|
||||
<Run Text=" Mbps"/>
|
||||
</TextBlock>
|
||||
<!-- Line 1: bitrate / fps · quality -->
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="FPS:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Style="{StaticResource YtLabel}"
|
||||
Foreground="White" Margin="0,0,20,0">
|
||||
<Run Text="{Binding CurrentHealth.FPS, Mode=OneWay, StringFormat={}{0:0}}"/>
|
||||
</TextBlock>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="Bitrate:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Style="{StaticResource YtLabel}"
|
||||
Foreground="White" Margin="0,0,20,0">
|
||||
<Run Text="{Binding CurrentHealth.CurrentBitrate, Mode=OneWay}"/>
|
||||
<Run Text=" Mbps"/>
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Text="Dropped:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="{Binding CurrentHealth.DroppedFrames}" Style="{StaticResource YtLabel}"
|
||||
Foreground="White" Margin="0,0,20,0"/>
|
||||
<TextBlock Text="FPS:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Style="{StaticResource YtLabel}"
|
||||
Foreground="White">
|
||||
<Run Text="{Binding CurrentHealth.FPS, Mode=OneWay, StringFormat={}{0:0}}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="Duration:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="{Binding CurrentHealth.StreamDuration}" Style="{StaticResource YtLabel}"
|
||||
Foreground="White"/>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<ComboBox Style="{StaticResource YtComboBox}" MinWidth="150"
|
||||
ItemsSource="{Binding QualityOptions}"
|
||||
SelectedItem="{Binding SelectedQuality}"
|
||||
DisplayMemberPath="Label"
|
||||
ToolTip="{Binding ResolutionHelp}"
|
||||
IsEnabled="{Binding IsOffline}"/>
|
||||
<Button ToolTip="Menu" Style="{StaticResource IconButton}" Click="GearButton_Click">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Save Layout" Command="{Binding SaveLayoutCommand}"/>
|
||||
<MenuItem Header="Save Layout As…" Command="{Binding SaveLayoutAsCommand}"/>
|
||||
<MenuItem Header="Open Layout…" Command="{Binding OpenLayoutCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="App Settings" Command="{Binding OpenSettingsCommand}"/>
|
||||
<MenuItem Header="Report Bug" Command="{Binding OpenBugCommand}"/>
|
||||
<MenuItem Header="Feature Request" Command="{Binding OpenFeatureCommand}"/>
|
||||
<MenuItem Header="About" Command="{Binding OpenAboutCommand}"/>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Path Data="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"
|
||||
Fill="#d0d0d0" Width="16" Height="16" Stretch="Uniform"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Text="{Binding CurrentHealth.HealthMessage}" Style="{StaticResource YtLabel}"
|
||||
Foreground="#e94560" Margin="20,0,0,0"/>
|
||||
</StackPanel>
|
||||
<!-- Line 2: dropped / duration (under bitrate / fps) + the MIC chip.
|
||||
Audio is KISS: desktop/game audio is automatic ("it just is" —
|
||||
WASAPI loopback at unity, zero UI). The creator's only audio
|
||||
control is the mic — meter, volume, mute. -->
|
||||
<Grid Grid.Row="1" Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<ComboBox Style="{StaticResource YtComboBox}" MinWidth="150"
|
||||
ItemsSource="{Binding QualityOptions}"
|
||||
SelectedItem="{Binding SelectedQuality}"
|
||||
DisplayMemberPath="Label"
|
||||
ToolTip="{Binding ResolutionHelp}"
|
||||
IsEnabled="{Binding IsOffline}"/>
|
||||
<Button ToolTip="Menu" Style="{StaticResource IconButton}" Click="GearButton_Click">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Save Layout" Command="{Binding SaveLayoutCommand}"/>
|
||||
<MenuItem Header="Save Layout As…" Command="{Binding SaveLayoutAsCommand}"/>
|
||||
<MenuItem Header="Open Layout…" Command="{Binding OpenLayoutCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="App Settings" Command="{Binding OpenSettingsCommand}"/>
|
||||
<MenuItem Header="Report Bug" Command="{Binding OpenBugCommand}"/>
|
||||
<MenuItem Header="Feature Request" Command="{Binding OpenFeatureCommand}"/>
|
||||
<MenuItem Header="About" Command="{Binding OpenAboutCommand}"/>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Path Data="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"
|
||||
Fill="#d0d0d0" Width="16" Height="16" Stretch="Uniform"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="Dropped:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="{Binding CurrentHealth.DroppedFrames}" Style="{StaticResource YtLabel}"
|
||||
Foreground="White" Margin="0,0,20,0"/>
|
||||
|
||||
<TextBlock Text="Duration:" Style="{StaticResource YtLabel}" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="{Binding CurrentHealth.StreamDuration}" Style="{StaticResource YtLabel}"
|
||||
Foreground="White"/>
|
||||
|
||||
<TextBlock Text="{Binding CurrentHealth.HealthMessage}" Style="{StaticResource YtLabel}"
|
||||
Foreground="#e94560" Margin="20,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Sound meter: plain filled bar, blank → green → yellow → red,
|
||||
with zone markers at the yellow (60%) and red (80%) starts. -->
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Text="MIC" Foreground="#a0a0b0" FontSize="11" FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||
<Border Width="360" Height="14" CornerRadius="7" Background="#1a1a2e" Margin="8,0,8,0"
|
||||
ClipToBounds="True" VerticalAlignment="Center">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" Width="{Binding MeterFillWidth}"
|
||||
Background="{Binding MeterBrush}"/>
|
||||
<Rectangle Width="2" Fill="#00000080" HorizontalAlignment="Left" Margin="216,0,0,0"
|
||||
VerticalAlignment="Stretch"/>
|
||||
<Rectangle Width="2" Fill="#00000080" HorizontalAlignment="Left" Margin="288,0,0,0"
|
||||
VerticalAlignment="Stretch"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Slider Width="130" Minimum="0" Maximum="1"
|
||||
Value="{Binding MicVolume, Mode=TwoWay}" VerticalAlignment="Center"/>
|
||||
<Button Content="{Binding MicMuteText}" Style="{StaticResource YtButtonSecondary}"
|
||||
Padding="10,3" Margin="8,0,0,0" Command="{Binding ToggleMicMuteCommand}"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user