diff --git a/src/TeamsISO.App.WinUI/Views/MainWindow.xaml.cs b/src/TeamsISO.App.WinUI/Views/MainWindow.xaml.cs
index a03cca3..22e6443 100644
--- a/src/TeamsISO.App.WinUI/Views/MainWindow.xaml.cs
+++ b/src/TeamsISO.App.WinUI/Views/MainWindow.xaml.cs
@@ -213,22 +213,35 @@ public sealed partial class MainWindow : Window
}
///
- /// Minimal participant row — name + ISO state + toggle button. Drops
- /// the brushed avatar / theme-resource lookups that may have been
- /// triggering the crash. The full visual row template comes back
- /// after we've verified the binding path works.
+ /// Participant row — name + ISO state pill, with the cyan-accent
+ /// left border when the participant is the active speaker, and the
+ /// pill background flipping green/coral/amber based on ISO state.
+ /// Imperative construction so we sidestep the WinUI 3 DataTemplate
+ /// parser path that crashes on this build host.
///
private static Microsoft.UI.Xaml.Controls.Grid BuildSimpleRow(ParticipantViewModel p)
{
var grid = new Microsoft.UI.Xaml.Controls.Grid
{
Height = 56,
- Padding = new Thickness(20, 0, 20, 0),
+ Padding = new Thickness(0, 0, 20, 0),
};
+ grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(3) });
+ grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(20) });
grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(1, Microsoft.UI.Xaml.GridUnitType.Star) });
- grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(120) });
+ grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(140) });
grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = Microsoft.UI.Xaml.GridLength.Auto });
+ // Active-speaker left accent. Visible only when IsActiveSpeaker
+ // flips on (driven by MainViewModel.OnStatsTick at 1Hz).
+ var accent = new Microsoft.UI.Xaml.Controls.Border
+ {
+ Background = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCyanText"],
+ Visibility = p.IsActiveSpeaker ? Visibility.Visible : Visibility.Collapsed,
+ };
+ Microsoft.UI.Xaml.Controls.Grid.SetColumn(accent, 0);
+ grid.Children.Add(accent);
+
var nameStack = new Microsoft.UI.Xaml.Controls.StackPanel
{
VerticalAlignment = VerticalAlignment.Center,
@@ -248,7 +261,7 @@ public sealed partial class MainWindow : Window
};
nameStack.Children.Add(nameText);
nameStack.Children.Add(codecText);
- Microsoft.UI.Xaml.Controls.Grid.SetColumn(nameStack, 0);
+ Microsoft.UI.Xaml.Controls.Grid.SetColumn(nameStack, 2);
grid.Children.Add(nameStack);
var outputText = new Microsoft.UI.Xaml.Controls.TextBlock
@@ -258,7 +271,7 @@ public sealed partial class MainWindow : Window
FontSize = 12,
VerticalAlignment = VerticalAlignment.Center,
};
- Microsoft.UI.Xaml.Controls.Grid.SetColumn(outputText, 1);
+ Microsoft.UI.Xaml.Controls.Grid.SetColumn(outputText, 3);
grid.Children.Add(outputText);
var pillText = new Microsoft.UI.Xaml.Controls.TextBlock
@@ -277,7 +290,8 @@ public sealed partial class MainWindow : Window
VerticalAlignment = VerticalAlignment.Center,
Content = pillText,
};
- Microsoft.UI.Xaml.Controls.Grid.SetColumn(pill, 2);
+ ApplyIsoPillStyling(pill, pillText, p.IsoStateLabel);
+ Microsoft.UI.Xaml.Controls.Grid.SetColumn(pill, 4);
grid.Children.Add(pill);
p.PropertyChanged += (_, e) =>
@@ -298,6 +312,12 @@ public sealed partial class MainWindow : Window
case nameof(ParticipantViewModel.IsoStateLabel):
case nameof(ParticipantViewModel.IsEnabled):
pillText.Text = p.IsoStateLabel;
+ ApplyIsoPillStyling(pill, pillText, p.IsoStateLabel);
+ break;
+ case nameof(ParticipantViewModel.IsActiveSpeaker):
+ accent.Visibility = p.IsActiveSpeaker
+ ? Visibility.Visible
+ : Visibility.Collapsed;
break;
}
});
@@ -306,6 +326,49 @@ public sealed partial class MainWindow : Window
return grid;
}
+ ///
+ /// Re-color the ISO pill based on the engine's reported state.
+ /// LIVE = green on green-tinted background. ERROR = coral on coral-
+ /// tinted background. STARTING = amber. NO SIGNAL = amber. OFF =
+ /// neutral surface. Mirrors the WPF host's IsoToggle data-trigger
+ /// behavior but built imperatively from theme-resource brush keys.
+ ///
+ private static void ApplyIsoPillStyling(
+ Microsoft.UI.Xaml.Controls.Button pill,
+ Microsoft.UI.Xaml.Controls.TextBlock pillText,
+ string state)
+ {
+ Microsoft.UI.Xaml.Media.Brush bg, border, fg;
+ switch (state)
+ {
+ case "LIVE":
+ bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusLiveBg"];
+ border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusLive"];
+ fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusLive"];
+ break;
+ case "ERROR":
+ bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCoralBg"];
+ border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCoral"];
+ fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCoral"];
+ break;
+ case "NO SIGNAL":
+ case "STARTING":
+ bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusWarnBg"];
+ border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusWarn"];
+ fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusWarn"];
+ break;
+ default: // OFF / —
+ bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BgSurface"];
+ border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BorderStrong"];
+ fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["FgPrimary"];
+ break;
+ }
+ pill.Background = bg;
+ pill.BorderBrush = border;
+ pill.BorderThickness = new Thickness(1);
+ pillText.Foreground = fg;
+ }
+
/// Full rich row template — replaces BuildSimpleRow once we've verified the simple version doesn't crash.
private static Microsoft.UI.Xaml.Controls.Grid BuildParticipantRow(ParticipantViewModel p)
{