Creator ruling 2026-11-12: "we don't care if a creator wants to edit their scene: move stuff around, shrink/grow a webcam view, etc. Why not?" Correct — the app was only ever *forcing* EDIT off at go-live, never enforcing it, so the gun-safety was a habit rather than a rule. App.LockEditWhileLive ships off: a show no longer takes EDIT away. Turning it on restores the old behaviour exactly — go-live flips EDIT off and stop flips it back, and only because the lock took it, so a creator who had already turned EDIT off does not get it handed back on stop. MainViewModel.ApplyEditLockForSession holds the rule so it is testable without starting a broadcast; EditWhileLiveTests covers both settings, the round trip, and the "don't hand it back" case. Settings → Editing carries the checkbox. This is the first slice of TASK 68 (editing while live). 678 pass, 0 warnings. Scope justification: Assets/starting-background.jpg is outside this unit — the creator's replacement art, still awaiting their visual check.
169 lines
13 KiB
XML
169 lines
13 KiB
XML
<UserControl x:Class="ytLive.Controls.SettingsDrawer"
|
||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||
xmlns:models="clr-namespace:ytLive.Models"
|
||
xmlns:services="clr-namespace:ytLive.Services"
|
||
xmlns:notification="clr-namespace:Notification.Core;assembly=Notification.Core">
|
||
<!-- App Settings, as a RIGHT-EDGE PULL-OUT (creator ruling 2026-11-01): the gear tab opens
|
||
this drawer immediately, in the same animated-width pattern as Stream Settings / YPP /
|
||
Socials / TEST. It used to be a centred modal overlay, which then needed its own scroll
|
||
viewer once the section list outgrew the shell — a drawer has the height of the preview
|
||
and that problem disappears.
|
||
|
||
Categories are headings; their controls are indented under them (Zoom is one). -->
|
||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||
<StackPanel Margin="0,0,0,0">
|
||
|
||
<!-- ═══ RECORDINGS ═══ -->
|
||
<TextBlock Text="Recordings" Style="{StaticResource SectionHeader}" Margin="0,0,0,4"/>
|
||
<TextBlock Text="Default location" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="10,0,0,2"/>
|
||
<DockPanel Margin="10,0,0,10">
|
||
<Button DockPanel.Dock="Right" Content="Browse…" Command="{Binding ChooseRecordFolderCommand}"
|
||
Style="{StaticResource YtButtonSecondary}" Padding="8,2" FontSize="11" Margin="6,0,0,0"/>
|
||
<Button DockPanel.Dock="Right" Content="Use Downloads" Command="{Binding ResetRecordFolderCommand}"
|
||
Style="{StaticResource YtButtonSecondary}" Padding="8,2" FontSize="11" Margin="6,0,0,0"/>
|
||
<TextBox Style="{StaticResource YtTextBoxCompact}" Text="{Binding RecordFolderDisplay, Mode=OneWay}"
|
||
IsReadOnly="True" Foreground="{StaticResource Brush.OnSurfaceVariant}" VerticalAlignment="Center"/>
|
||
</DockPanel>
|
||
|
||
<TextBlock Text="Slide-out alerts" Style="{StaticResource SectionHeader}" Margin="0,6,0,4"/>
|
||
<TextBlock Text="Position" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="10,0,0,2"/>
|
||
<ComboBox Style="{StaticResource YtComboBox}" Margin="10,0,0,8"
|
||
SelectedValue="{Binding ToastPosition, Mode=TwoWay}" SelectedValuePath="Tag"
|
||
ToolTip="Choose where notifications appear inside the app window.">
|
||
<ComboBoxItem Content="Top left" Tag="{x:Static notification:NotificationPosition.TopLeft}"/>
|
||
<ComboBoxItem Content="Top right" Tag="{x:Static notification:NotificationPosition.TopRight}"/>
|
||
<ComboBoxItem Content="Center left" Tag="{x:Static notification:NotificationPosition.CenterLeft}"/>
|
||
<ComboBoxItem Content="Center right" Tag="{x:Static notification:NotificationPosition.CenterRight}"/>
|
||
<ComboBoxItem Content="Bottom left" Tag="{x:Static notification:NotificationPosition.BottomLeft}"/>
|
||
<ComboBoxItem Content="Bottom right" Tag="{x:Static notification:NotificationPosition.BottomRight}"/>
|
||
</ComboBox>
|
||
<CheckBox Content="Keep alerts until dismissed" Style="{StaticResource PropertyPillCheck}"
|
||
Margin="12,2,0,2" IsChecked="{Binding StickyAlertsUntilDismissed, Mode=TwoWay}"
|
||
ToolTip="When on, every slide-out alert stays until you click it or close it."/>
|
||
<TextBlock Text="Off: informational alerts use their normal timeouts; errors still stay until closed."
|
||
Style="{StaticResource PropertyHint}" Margin="10,0,0,8"/>
|
||
|
||
<!-- ═══ BRAND ═══ -->
|
||
<TextBlock Text="Brand logo" Style="{StaticResource SectionHeader}" Margin="0,6,0,4"/>
|
||
<TextBlock Text="Image file (shown on every scene)" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="10,0,0,2"/>
|
||
<DockPanel Margin="10,0,0,10">
|
||
<Button DockPanel.Dock="Right" Content="Browse…" Command="{Binding BrowseBrandLogoCommand}"
|
||
Style="{StaticResource YtButtonSecondary}" Padding="8,2" FontSize="11" Margin="6,0,0,0"/>
|
||
<!-- A file NAME says nothing about the picture. The thumbnail shows what is set;
|
||
hovering enlarges it, a click collapses it again. -->
|
||
<Border x:Name="BrandLogoThumbFrame" DockPanel.Dock="Left" Width="28" Height="28"
|
||
Margin="0,0,6,0" CornerRadius="4" ClipToBounds="True"
|
||
Background="{StaticResource Brush.SurfaceContainerLowest}"
|
||
BorderBrush="{StaticResource Brush.Outline}" BorderThickness="1"
|
||
Cursor="Hand" ToolTip="Hover to enlarge — click to close"
|
||
Visibility="{Binding BrandLogoPreviewImage, Converter={StaticResource NotNullToVis}}">
|
||
<Image x:Name="BrandLogoThumbImage" Source="{Binding BrandLogoPreviewImage}"
|
||
Stretch="Uniform" MouseEnter="BrandLogoThumb_MouseEnter"
|
||
MouseLeave="BrandLogoThumb_MouseLeave"
|
||
MouseLeftButtonUp="BrandLogoThumb_Click"/>
|
||
</Border>
|
||
<TextBox Style="{StaticResource YtTextBoxCompact}" Text="{Binding BrandLogoFileDisplay, Mode=OneWay}"
|
||
IsReadOnly="True" Foreground="{StaticResource Brush.OnSurfaceVariant}" VerticalAlignment="Center"/>
|
||
</DockPanel>
|
||
<Popup x:Name="BrandLogoPreviewPopup" PlacementTarget="{Binding ElementName=BrandLogoThumbFrame}"
|
||
Placement="Left" HorizontalOffset="-6" StaysOpen="True" AllowsTransparency="True"
|
||
IsHitTestVisible="True" MouseLeave="BrandLogoPreviewPopup_MouseLeave">
|
||
<Border Padding="6" CornerRadius="6"
|
||
Background="{StaticResource Brush.SurfaceContainerHighest}"
|
||
BorderBrush="{StaticResource Brush.Outline}" BorderThickness="1">
|
||
<StackPanel>
|
||
<Image Source="{Binding BrandLogoPreviewImage}" MaxWidth="420" MaxHeight="320"
|
||
Stretch="Uniform" RenderOptions.BitmapScalingMode="HighQuality"/>
|
||
<TextBlock Text="{Binding BrandLogoFileDisplay}" FontSize="11" Margin="0,6,0,0"
|
||
Foreground="{StaticResource Brush.OnSurfaceVariant}"/>
|
||
</StackPanel>
|
||
</Border>
|
||
</Popup>
|
||
|
||
<!-- ═══ ZOOM ═══ -->
|
||
<TextBlock Text="Clips" Style="{StaticResource SectionHeader}" Margin="0,10,0,4"/>
|
||
<CheckBox Content="Save replay clips" Style="{StaticResource PropertyPillCheck}" Margin="12,2,0,4"
|
||
IsChecked="{Binding ClipsEnabled, Mode=TwoWay}"
|
||
ToolTip="F10 saves the last few seconds of the show. Off by default; nothing runs while it is off."/>
|
||
<StackPanel Margin="12,0,0,4" IsEnabled="{Binding ClipsEnabled}">
|
||
<TextBlock Text="Clip length" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="0,0,0,2"/>
|
||
<ComboBox ItemsSource="{Binding ClipLengthOptions}" SelectedItem="{Binding ClipLengthText, Mode=TwoWay}"
|
||
Style="{StaticResource YtComboBox}" Height="28" Margin="0,0,0,6"/>
|
||
<TextBlock Text="Keep" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="0,0,0,2"/>
|
||
<ComboBox ItemsSource="{Binding ClipKeepOptions}" SelectedItem="{Binding ClipKeepText, Mode=TwoWay}"
|
||
Style="{StaticResource YtComboBox}" Height="28"/>
|
||
<TextBlock Text="A capture, not an editor: for trimming, captions or a library, use a video editor."
|
||
Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="10" TextWrapping="Wrap" Margin="0,6,0,0"/>
|
||
</StackPanel>
|
||
|
||
<TextBlock Text="Zoom" Style="{StaticResource SectionHeader}" Margin="0,6,0,4"/>
|
||
|
||
<TextBlock Text="Zoom view shape" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="10,0,0,2"/>
|
||
<ComboBox Style="{StaticResource YtComboBox}" Margin="10,0,0,8" SelectedValue="{Binding ZoomShape}" SelectedValuePath="Tag">
|
||
<ComboBoxItem Content="Circle" Tag="{x:Static models:ZoomShape.Circle}"/>
|
||
<ComboBoxItem Content="Phone (Vertical Rectangle)" Tag="{x:Static models:ZoomShape.VerticalRectangle}"/>
|
||
<ComboBoxItem Content="Tablet (Horizontal Rectangle)" Tag="{x:Static models:ZoomShape.HorizontalRectangle}"/>
|
||
</ComboBox>
|
||
|
||
<DockPanel Margin="10,0,0,10">
|
||
<ToggleButton DockPanel.Dock="Right" Style="{StaticResource PillToggle}"
|
||
IsChecked="{Binding ZoomFollowsBox, Mode=TwoWay}" VerticalAlignment="Center"
|
||
ToolTip="Off: the box magnifies the area you clicked. On: it magnifies whatever it hovers over."/>
|
||
<TextBlock Text="Zoom box follows" Foreground="{StaticResource Brush.OnSurface}" FontSize="11" VerticalAlignment="Center"/>
|
||
</DockPanel>
|
||
|
||
<!-- ═══ VIDEO CLIPS (TASK 64) ═══ -->
|
||
<TextBlock Text="Video clips" Style="{StaticResource SectionHeader}" Margin="0,6,0,4"/>
|
||
<DockPanel Margin="10,0,0,10">
|
||
<ToggleButton DockPanel.Dock="Right" Style="{StaticResource PillToggle}"
|
||
IsChecked="{Binding AutoChromaScreen, Mode=TwoWay}" VerticalAlignment="Center"
|
||
ToolTip="On: a clip shot against a clear green or blue screen is keyed as soon as it is added. Off: the app asks first."/>
|
||
<StackPanel>
|
||
<TextBlock Text="Auto Green/Blue Screen" Foreground="{StaticResource Brush.OnSurface}" FontSize="11"/>
|
||
<TextBlock Text="Removes a detected screen without asking." Style="{StaticResource PropertyHint}"/>
|
||
</StackPanel>
|
||
</DockPanel>
|
||
|
||
<!-- ═══ SCENE TRANSITIONS ═══ -->
|
||
<TextBlock Text="Scene transition" Style="{StaticResource SectionHeader}" Margin="0,6,0,4"/>
|
||
<TextBlock Text="Type" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" Margin="10,0,0,2"/>
|
||
<ComboBox Style="{StaticResource YtComboBox}" Margin="10,0,0,8" SelectedValue="{Binding SelectedTransitionType}" SelectedValuePath="Tag">
|
||
<ComboBoxItem Content="Cut" Tag="{x:Static services:TransitionType.Cut}"/>
|
||
<ComboBoxItem Content="Fade" Tag="{x:Static services:TransitionType.Fade}"/>
|
||
<ComboBoxItem Content="Move" Tag="{x:Static services:TransitionType.Move}"/>
|
||
<ComboBoxItem Content="Wipe" Tag="{x:Static services:TransitionType.Wipe}"/>
|
||
</ComboBox>
|
||
<DockPanel Margin="10,0,0,10">
|
||
<TextBlock DockPanel.Dock="Right" Foreground="{StaticResource Brush.OnSurfaceVariant}" FontSize="11" VerticalAlignment="Center" Margin="8,0,0,0" Width="56">
|
||
<Run Text="{Binding TransitionDurationMs, StringFormat={}{0:0}}"/><Run Text=" ms"/>
|
||
</TextBlock>
|
||
<Slider Minimum="100" Maximum="2000" TickFrequency="50" IsSnapToTickEnabled="True"
|
||
Value="{Binding TransitionDurationMs, Mode=TwoWay}" VerticalAlignment="Center"/>
|
||
</DockPanel>
|
||
|
||
<!-- ═══ LAYOUT DEFAULTS (TASK 37) ═══ -->
|
||
<TextBlock Text="Editing" Style="{StaticResource SectionHeader}" Margin="0,10,0,4"/>
|
||
<CheckBox IsChecked="{Binding LockEditWhileLive, Mode=TwoWay}" Margin="10,0,0,2"
|
||
Style="{StaticResource PropertyPillCheck}"
|
||
Content="Lock editing while recording or live"/>
|
||
<TextBlock Text="Off: layers can be moved or resized during a show. On: going live turns EDIT off and stopping turns it back on."
|
||
Style="{StaticResource PropertyHint}" Margin="28,0,0,10"/>
|
||
|
||
<TextBlock Text="Layout defaults" Style="{StaticResource SectionHeader}" Margin="0,10,0,4"/>
|
||
<TextBlock Text="Replaces every scene and layer with this build’s factory layout. Your selected webcam stays the same."
|
||
Style="{StaticResource PropertyHint}" Margin="10,0,0,6"/>
|
||
<Button Content="Restore staged scene" Command="{Binding RestoreStagedSceneDefaultsCommand}"
|
||
Style="{StaticResource YtButtonSecondary}" Margin="10,0,0,4" HorizontalAlignment="Left"/>
|
||
<TextBlock Text="Resets only the scene currently staged in the preview."
|
||
Style="{StaticResource PropertyHint}" Margin="10,0,0,8"/>
|
||
<Button Content="Restore all scenes" Command="{Binding RestoreAllLayoutDefaultsCommand}"
|
||
Style="{StaticResource YtButtonSecondary}" Margin="10,0,0,10" HorizontalAlignment="Left"/>
|
||
|
||
<!-- Development panel host. Empty in a Release build: the panel itself is excluded
|
||
from the Release compile, and the code-behind only fills this inside #if DEBUG. -->
|
||
<StackPanel x:Name="DeveloperPanelHost"/>
|
||
</StackPanel>
|
||
</ScrollViewer>
|
||
</UserControl>
|