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"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="TeamsISO" Height="600" Width="900">
|
||||
<Grid>
|
||||
<TextBlock Text="TeamsISO — Phase A scaffold (UI implemented in Phase C)"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
FontSize="16" Foreground="#444"/>
|
||||
</Grid>
|
||||
xmlns:vm="clr-namespace:TeamsISO.App.ViewModels"
|
||||
xmlns:conv="clr-namespace:TeamsISO.App.Converters"
|
||||
Title="TeamsISO" Height="700" Width="1100"
|
||||
Background="#202225" Foreground="#E8E8E8">
|
||||
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Windows;
|
||||
using TeamsISO.App.ViewModels;
|
||||
|
||||
namespace TeamsISO.App;
|
||||
|
||||
|
|
@ -8,4 +9,9 @@ public partial class MainWindow : Window
|
|||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public MainWindow(MainViewModel viewModel) : this()
|
||||
{
|
||||
DataContext = viewModel;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue