feat(winui3): colored ISO pills + active-speaker accent on rows
Some checks failed
CI / build-and-test (push) Has been cancelled
Some checks failed
CI / build-and-test (push) Has been cancelled
Two visual upgrades on the participant rows:
* The ISO state pill now flips background / border / text colors
based on the engine's reported state — green for LIVE, coral for
ERROR, amber for STARTING / NO SIGNAL, neutral surface for OFF.
Brushes pulled from the ThemeResource ramp (StatusLiveBg /
StatusLive / AccentCoralBg / AccentCoral / StatusWarnBg /
StatusWarn / BgSurface / BorderStrong). Mirrors the WPF host's
IsoToggle data-trigger behavior but built imperatively.
* The active-speaker left accent — a 3px cyan border at the row's
left edge — appears when MainViewModel's 1Hz stats tick marks the
loudest participant. Hidden by default; flips Visibility on
PropertyChanged(IsActiveSpeaker).
Row layout extended to accommodate: column 0 = 3px accent strip,
column 1 = 20px spacer, column 2 = name + codec (1*), column 3 =
output name (140px fixed), column 4 = ISO pill (auto).
ApplyIsoPillStyling is the brush-mapping helper — called once at row
construct and again on every IsoStateLabel / IsEnabled change. The
brush keys all resolve via Application.Current.Resources rather than
ThemeResource markup since the row is constructed imperatively (no
XAML to apply ThemeResource markup against).
Verified end-to-end: dotnet build clean, app launches with 3 live
participants in the row, all pills showing OFF (neutral surface +
strong border). Once a participant goes through OFF → STARTING (amber)
→ LIVE (green), the pill colors will update on the 1Hz stats tick.
This commit is contained in:
parent
f7249c31c2
commit
9ae14c8ee9
1 changed files with 72 additions and 9 deletions
|
|
@ -213,22 +213,35 @@ public sealed partial class MainWindow : Window
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimal participant row — name + ISO state + toggle button. Drops
|
/// Participant row — name + ISO state pill, with the cyan-accent
|
||||||
/// the brushed avatar / theme-resource lookups that may have been
|
/// left border when the participant is the active speaker, and the
|
||||||
/// triggering the crash. The full visual row template comes back
|
/// pill background flipping green/coral/amber based on ISO state.
|
||||||
/// after we've verified the binding path works.
|
/// Imperative construction so we sidestep the WinUI 3 DataTemplate
|
||||||
|
/// parser path that crashes on this build host.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Microsoft.UI.Xaml.Controls.Grid BuildSimpleRow(ParticipantViewModel p)
|
private static Microsoft.UI.Xaml.Controls.Grid BuildSimpleRow(ParticipantViewModel p)
|
||||||
{
|
{
|
||||||
var grid = new Microsoft.UI.Xaml.Controls.Grid
|
var grid = new Microsoft.UI.Xaml.Controls.Grid
|
||||||
{
|
{
|
||||||
Height = 56,
|
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(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 });
|
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
|
var nameStack = new Microsoft.UI.Xaml.Controls.StackPanel
|
||||||
{
|
{
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
|
@ -248,7 +261,7 @@ public sealed partial class MainWindow : Window
|
||||||
};
|
};
|
||||||
nameStack.Children.Add(nameText);
|
nameStack.Children.Add(nameText);
|
||||||
nameStack.Children.Add(codecText);
|
nameStack.Children.Add(codecText);
|
||||||
Microsoft.UI.Xaml.Controls.Grid.SetColumn(nameStack, 0);
|
Microsoft.UI.Xaml.Controls.Grid.SetColumn(nameStack, 2);
|
||||||
grid.Children.Add(nameStack);
|
grid.Children.Add(nameStack);
|
||||||
|
|
||||||
var outputText = new Microsoft.UI.Xaml.Controls.TextBlock
|
var outputText = new Microsoft.UI.Xaml.Controls.TextBlock
|
||||||
|
|
@ -258,7 +271,7 @@ public sealed partial class MainWindow : Window
|
||||||
FontSize = 12,
|
FontSize = 12,
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
};
|
};
|
||||||
Microsoft.UI.Xaml.Controls.Grid.SetColumn(outputText, 1);
|
Microsoft.UI.Xaml.Controls.Grid.SetColumn(outputText, 3);
|
||||||
grid.Children.Add(outputText);
|
grid.Children.Add(outputText);
|
||||||
|
|
||||||
var pillText = new Microsoft.UI.Xaml.Controls.TextBlock
|
var pillText = new Microsoft.UI.Xaml.Controls.TextBlock
|
||||||
|
|
@ -277,7 +290,8 @@ public sealed partial class MainWindow : Window
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
Content = pillText,
|
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);
|
grid.Children.Add(pill);
|
||||||
|
|
||||||
p.PropertyChanged += (_, e) =>
|
p.PropertyChanged += (_, e) =>
|
||||||
|
|
@ -298,6 +312,12 @@ public sealed partial class MainWindow : Window
|
||||||
case nameof(ParticipantViewModel.IsoStateLabel):
|
case nameof(ParticipantViewModel.IsoStateLabel):
|
||||||
case nameof(ParticipantViewModel.IsEnabled):
|
case nameof(ParticipantViewModel.IsEnabled):
|
||||||
pillText.Text = p.IsoStateLabel;
|
pillText.Text = p.IsoStateLabel;
|
||||||
|
ApplyIsoPillStyling(pill, pillText, p.IsoStateLabel);
|
||||||
|
break;
|
||||||
|
case nameof(ParticipantViewModel.IsActiveSpeaker):
|
||||||
|
accent.Visibility = p.IsActiveSpeaker
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Collapsed;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -306,6 +326,49 @@ public sealed partial class MainWindow : Window
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Full rich row template — replaces BuildSimpleRow once we've verified the simple version doesn't crash.</summary>
|
/// <summary>Full rich row template — replaces BuildSimpleRow once we've verified the simple version doesn't crash.</summary>
|
||||||
private static Microsoft.UI.Xaml.Controls.Grid BuildParticipantRow(ParticipantViewModel p)
|
private static Microsoft.UI.Xaml.Controls.Grid BuildParticipantRow(ParticipantViewModel p)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue