Replace three-button cluster with a single context-aware primary button

Button follows the user journey: 'Connect to YouTube' (not signed in)
-> 'Go Live' (connected, idle) -> 'Stop Stream' (live).
This commit is contained in:
2026-08-04 10:35:00 -07:00
parent 8ee44f571e
commit 4293ae11a4
2 changed files with 31 additions and 41 deletions
+3 -31
View File
@@ -119,38 +119,10 @@
</StackPanel> </StackPanel>
</Border> </Border>
<!-- Stream Controls --> <!-- Primary action: single button, adapts to state -->
<StackPanel Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Center"> <StackPanel Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Center">
<Button Content="{Binding PrimaryButtonText}" Style="{StaticResource YtButton}"
<!-- YouTube connection status light + button --> Command="{Binding PrimaryCommand}"/>
<Border Background="#0f3460" CornerRadius="4" Padding="8,6" Margin="0,0,12,0"
VerticalAlignment="Center" ToolTip="YouTube connection status">
<StackPanel Orientation="Horizontal">
<Ellipse Width="10" Height="10" Margin="0,0,8,0" VerticalAlignment="Center">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="#555"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsYouTubeConnected}" Value="True">
<Setter Property="Fill" Value="#00ff00"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Button Content="YouTube" Style="{StaticResource YtButtonSecondary}"
Background="Transparent" Padding="0"
Command="{Binding ConnectYouTubeCommand}"
ToolTip="Sign in to YouTube (optional)"/>
</StackPanel>
</Border>
<Button Content="Go Live" Style="{StaticResource YtButton}"
Command="{Binding StartStreamCommand}"
Visibility="{Binding IsOffline, Converter={StaticResource BoolToVis}}"/>
<Button Content="Stop Stream" Style="{StaticResource YtButton}"
Background="#333" Command="{Binding StopStreamCommand}"
Visibility="{Binding IsLive, Converter={StaticResource BoolToVis}}"/>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Border> </Border>
+28 -10
View File
@@ -38,6 +38,7 @@ public class MainViewModel : ViewModelBase
OnPropertyChanged(nameof(IsOffline)); OnPropertyChanged(nameof(IsOffline));
OnPropertyChanged(nameof(IsLive)); OnPropertyChanged(nameof(IsLive));
OnPropertyChanged(nameof(StatusDisplay)); OnPropertyChanged(nameof(StatusDisplay));
OnPropertyChanged(nameof(PrimaryButtonText));
} }
} }
} }
@@ -66,7 +67,11 @@ public class MainViewModel : ViewModelBase
public bool IsYouTubeConnected public bool IsYouTubeConnected
{ {
get => _isYouTubeConnected; get => _isYouTubeConnected;
set => SetProperty(ref _isYouTubeConnected, value); set
{
if (SetProperty(ref _isYouTubeConnected, value))
OnPropertyChanged(nameof(PrimaryButtonText));
}
} }
public string StatusDisplay => StreamStatus switch public string StatusDisplay => StreamStatus switch
@@ -78,12 +83,20 @@ public class MainViewModel : ViewModelBase
_ => "UNKNOWN" _ => "UNKNOWN"
}; };
/// <summary>
/// Single, context-aware primary button. Follows the user's journey:
/// not connected → connect, connected+idle → go live, live → stop.
/// </summary>
public string PrimaryButtonText => !IsYouTubeConnected
? "Connect to YouTube"
: IsLive
? "Stop Stream"
: "Go Live";
// Commands // Commands
public ICommand AddSceneCommand { get; } public ICommand AddSceneCommand { get; }
public ICommand RemoveSceneCommand { get; } public ICommand RemoveSceneCommand { get; }
public ICommand StartStreamCommand { get; } public ICommand PrimaryCommand { get; }
public ICommand StopStreamCommand { get; }
public ICommand ConnectYouTubeCommand { get; }
public MainViewModel() public MainViewModel()
{ {
@@ -95,9 +108,7 @@ public class MainViewModel : ViewModelBase
AddSceneCommand = new RelayCommand(_ => AddScene()); AddSceneCommand = new RelayCommand(_ => AddScene());
RemoveSceneCommand = new RelayCommand(scene => RemoveScene(scene as Scene)); RemoveSceneCommand = new RelayCommand(scene => RemoveScene(scene as Scene));
StartStreamCommand = new RelayCommand(_ => StartStream(), _ => StreamStatus == StreamStatus.Offline); PrimaryCommand = new RelayCommand(_ => PrimaryAction());
StopStreamCommand = new RelayCommand(_ => StopStream(), _ => StreamStatus == StreamStatus.Streaming);
ConnectYouTubeCommand = new RelayCommand(_ => ConnectYouTube());
// Start with a default scene // Start with a default scene
AddScene("Scene 1"); AddScene("Scene 1");
@@ -131,19 +142,16 @@ public class MainViewModel : ViewModelBase
private async void StartStream() private async void StartStream()
{ {
StreamStatus = StreamStatus.Connecting; StreamStatus = StreamStatus.Connecting;
OnPropertyChanged(nameof(StatusDisplay));
// TODO: Initialize capture pipeline, encode, and push to RTMP // TODO: Initialize capture pipeline, encode, and push to RTMP
// For now, simulate connection // For now, simulate connection
await Task.Delay(500); await Task.Delay(500);
StreamStatus = StreamStatus.Streaming; StreamStatus = StreamStatus.Streaming;
OnPropertyChanged(nameof(StatusDisplay));
} }
private void StopStream() private void StopStream()
{ {
StreamStatus = StreamStatus.Offline; StreamStatus = StreamStatus.Offline;
OnPropertyChanged(nameof(StatusDisplay));
} }
private void ConnectYouTube() private void ConnectYouTube()
@@ -152,4 +160,14 @@ public class MainViewModel : ViewModelBase
// For now, this is a stub // For now, this is a stub
IsYouTubeConnected = false; IsYouTubeConnected = false;
} }
private void PrimaryAction()
{
if (!IsYouTubeConnected)
ConnectYouTube();
else if (IsLive)
StopStream();
else
StartStream();
}
} }