feat(ui): add MainWindow XAML with participants DataGrid, settings sidebar, alert banner
Some checks failed
CI / build-and-test (push) Failing after 34s
Some checks failed
CI / build-and-test (push) Failing after 34s
This commit is contained in:
parent
8c441318d8
commit
d64b110550
4 changed files with 231 additions and 6 deletions
18
src/TeamsISO.App/Converters/BoolToVisibilityConverter.cs
Normal file
18
src/TeamsISO.App/Converters/BoolToVisibilityConverter.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace TeamsISO.App.Converters;
|
||||||
|
|
||||||
|
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||||
|
public sealed class BoolToVisibilityConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public Visibility TrueValue { get; set; } = Visibility.Visible;
|
||||||
|
public Visibility FalseValue { get; set; } = Visibility.Collapsed;
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
|
||||||
|
value is true ? TrueValue : FalseValue;
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
52
src/TeamsISO.App/Converters/EnumDescriptionConverter.cs
Normal file
52
src/TeamsISO.App/Converters/EnumDescriptionConverter.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using TeamsISO.Engine.Domain;
|
||||||
|
|
||||||
|
namespace TeamsISO.App.Converters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renders engine enum values into operator-friendly strings.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EnumDescriptionConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value switch
|
||||||
|
{
|
||||||
|
TargetFramerate fr => fr switch
|
||||||
|
{
|
||||||
|
TargetFramerate.Fps23_976 => "23.976 fps",
|
||||||
|
TargetFramerate.Fps24 => "24 fps",
|
||||||
|
TargetFramerate.Fps25 => "25 fps",
|
||||||
|
TargetFramerate.Fps29_97 => "29.97 fps",
|
||||||
|
TargetFramerate.Fps30 => "30 fps",
|
||||||
|
TargetFramerate.Fps50 => "50 fps",
|
||||||
|
TargetFramerate.Fps59_94 => "59.94 fps",
|
||||||
|
TargetFramerate.Fps60 => "60 fps",
|
||||||
|
_ => fr.ToString()
|
||||||
|
},
|
||||||
|
TargetResolution r => r switch
|
||||||
|
{
|
||||||
|
TargetResolution.R720p => "720p",
|
||||||
|
TargetResolution.R1080p => "1080p",
|
||||||
|
TargetResolution.R4K => "4K",
|
||||||
|
_ => r.ToString()
|
||||||
|
},
|
||||||
|
AspectMode a => a switch
|
||||||
|
{
|
||||||
|
AspectMode.Pillarbox => "Pillarbox",
|
||||||
|
AspectMode.Letterbox => "Letterbox",
|
||||||
|
AspectMode.Stretch => "Stretch",
|
||||||
|
_ => a.ToString()
|
||||||
|
},
|
||||||
|
AudioMode m => m switch
|
||||||
|
{
|
||||||
|
AudioMode.Auto => "Auto (isolated → mixed fallback)",
|
||||||
|
AudioMode.Isolated => "Isolated",
|
||||||
|
AudioMode.Mixed => "Mixed",
|
||||||
|
_ => m.ToString()
|
||||||
|
},
|
||||||
|
_ => value
|
||||||
|
};
|
||||||
|
|
||||||
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) =>
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,159 @@
|
||||||
<Window x:Class="TeamsISO.App.MainWindow"
|
<Window x:Class="TeamsISO.App.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
Title="TeamsISO" Height="600" Width="900">
|
xmlns:vm="clr-namespace:TeamsISO.App.ViewModels"
|
||||||
<Grid>
|
xmlns:conv="clr-namespace:TeamsISO.App.Converters"
|
||||||
<TextBlock Text="TeamsISO — Phase A scaffold (UI implemented in Phase C)"
|
Title="TeamsISO" Height="700" Width="1100"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
Background="#202225" Foreground="#E8E8E8">
|
||||||
FontSize="16" Foreground="#444"/>
|
|
||||||
</Grid>
|
<Window.Resources>
|
||||||
|
<conv:BoolToVisibilityConverter x:Key="BoolToVis" />
|
||||||
|
<conv:EnumDescriptionConverter x:Key="EnumDesc" />
|
||||||
|
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="#E8E8E8"/>
|
||||||
|
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||||
|
<Setter Property="FontSize" Value="13"/>
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="Button">
|
||||||
|
<Setter Property="Padding" Value="10,4"/>
|
||||||
|
<Setter Property="Margin" Value="0,4,0,0"/>
|
||||||
|
<Setter Property="Background" Value="#3F4147"/>
|
||||||
|
<Setter Property="Foreground" Value="#E8E8E8"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#5A5C63"/>
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="ComboBox">
|
||||||
|
<Setter Property="Margin" Value="0,2,0,8"/>
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
|
<DockPanel>
|
||||||
|
|
||||||
|
<!-- Alert banner -->
|
||||||
|
<Border DockPanel.Dock="Top"
|
||||||
|
Background="#7A2B2B"
|
||||||
|
Padding="12,8"
|
||||||
|
Visibility="{Binding AlertBanner.IsVisible, Converter={StaticResource BoolToVis}}">
|
||||||
|
<DockPanel>
|
||||||
|
<Button DockPanel.Dock="Right"
|
||||||
|
Content="Dismiss"
|
||||||
|
Command="{Binding AlertBanner.DismissCommand}"
|
||||||
|
Margin="12,0,0,0"/>
|
||||||
|
<TextBlock Text="{Binding AlertBanner.Message}"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Status footer -->
|
||||||
|
<Border DockPanel.Dock="Bottom" Background="#191B1F" Padding="10,6">
|
||||||
|
<TextBlock Text="{Binding StatusText}" FontStyle="Italic" Foreground="#A0A0A0"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Settings sidebar -->
|
||||||
|
<Border DockPanel.Dock="Right" Background="#2A2C32" Width="320" Padding="14">
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="Global Settings" FontSize="16" FontWeight="Bold" Margin="0,0,0,12"/>
|
||||||
|
|
||||||
|
<TextBlock Text="Target Framerate"/>
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
<ComboBox ItemsSource="{Binding Settings.AvailableAudioModes}"
|
||||||
|
SelectedItem="{Binding Settings.Audio}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Converter={StaticResource EnumDesc}}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
|
||||||
|
<Button Content="Apply" Command="{Binding Settings.ApplyCommand}" Margin="0,16,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Main content: participants list -->
|
||||||
|
<Grid Margin="14">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0"
|
||||||
|
Text="Participants"
|
||||||
|
FontSize="16" FontWeight="Bold"
|
||||||
|
Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<DataGrid Grid.Row="1"
|
||||||
|
ItemsSource="{Binding Participants}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
Background="#2A2C32"
|
||||||
|
Foreground="#E8E8E8"
|
||||||
|
RowBackground="#2A2C32"
|
||||||
|
AlternatingRowBackground="#2E3037"
|
||||||
|
BorderBrush="#5A5C63"
|
||||||
|
GridLinesVisibility="Horizontal"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
CanUserAddRows="False" CanUserDeleteRows="False"
|
||||||
|
RowHeight="34">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Display Name" Binding="{Binding DisplayName}" Width="2*" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="Source" Binding="{Binding SourceMachine}" Width="*" IsReadOnly="True"/>
|
||||||
|
<DataGridTextColumn Header="ISO Output Name" Binding="{Binding CustomName, UpdateSourceTrigger=PropertyChanged}" Width="2*"/>
|
||||||
|
<DataGridTemplateColumn Header="ISO" Width="100">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Button Content="{Binding IsEnabled, StringFormat={}{0}}" Command="{Binding ToggleIsoCommand}">
|
||||||
|
<Button.Style>
|
||||||
|
<Style TargetType="Button">
|
||||||
|
<Setter Property="Content" Value="Enable"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsEnabled}" Value="True">
|
||||||
|
<Setter Property="Content" Value="Disable"/>
|
||||||
|
<Setter Property="Background" Value="#3D6F45"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding IsProcessing}" Value="True">
|
||||||
|
<Setter Property="Content" Value="…"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using TeamsISO.App.ViewModels;
|
||||||
|
|
||||||
namespace TeamsISO.App;
|
namespace TeamsISO.App;
|
||||||
|
|
||||||
|
|
@ -8,4 +9,9 @@ public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MainWindow(MainViewModel viewModel) : this()
|
||||||
|
{
|
||||||
|
DataContext = viewModel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue