dragon-iso/src/TeamsISO.App.WinUI/Views/MainWindow.xaml

520 lines
27 KiB
Text
Raw Normal View History

feat(winui3): scaffold TeamsISO.App.WinUI alongside the WPF host First step of the WinUI 3 replatform per the approved redesign brief. The new project coexists with the existing src/TeamsISO.App (WPF) so the WPF host keeps building and shipping while the WinUI 3 redesign lands incrementally. Once the WinUI 3 build is feature-complete and tested against a real Teams meeting, the WPF project is retired. Scaffold contents: * src/TeamsISO.App.WinUI/TeamsISO.App.WinUI.csproj Windows App SDK 1.6 LTS (250602001), unpackaged mode (WindowsPackageType=None) so the existing MSI installer keeps working. Target framework net8.0-windows10.0.19041.0, min platform 10.0.17763.0 to preserve Win10 1809+ compatibility for working broadcast hardware. Pins WindowsSdkPackageVersion=10.0.19041.38 so .NET SDK 8.0.301 builds cleanly without an SDK upgrade on the build host. * src/TeamsISO.App.WinUI/app.manifest PerMonitorV2 DPI awareness + gdiScaling for crisp text on high-DPI broadcast monitors. asInvoker trust level (control surface :9755 and OSC :9000 bind to 127.0.0.1, no admin needed). * App.xaml + App.xaml.cs Minimal startup: brings up MainWindow. The full pipeline (NDI runtime preflight, IsoController wiring, single-instance mutex, REST + OSC bridge, tray icon, crash diagnostics, auto-update banner, onboarding) migrates in subsequent commits. * Themes/Tokens.xaml Wild Dragon design tokens as ThemeDictionary entries (Default = Dark, Light). Colors as Color resources, Brushes paired per theme so {ThemeResource} auto-swaps when RequestedTheme flips — no app restart, no flicker. Spacing/radii/typography tokens are theme-agnostic at the outer level. Light palette maintains brand recognition via cyan-tinted off-whites (#FAFAFB canvas, #F0F1F3 rail) rather than pure white, and splits cyan into accent.cyan.surface (#97EDF0, works in both modes because text on top is near-black) and accent.cyan.text (#97EDF0 dark / #0E7C82 light) so captions and inline labels keep AA contrast. * Themes/Controls.xaml Button hierarchy with real commitments: Primary (cyan fill, one per surface), Secondary (transparent bordered), Tertiary (text only), Destructive (coral border + text), Caption (titlebar), RailIcon. Typographic ramp (Display / Title / Heading / Body / Subtle / Caption / Mono) at the DESIGN.md 1.25 ratio. * CommunityToolkit.WinUI.UI.Controls.DataGrid 7.1.2 referenced for the participants table migration. (Toolkit 8.x dropped DataGrid; 7.x is the only currently-maintained free option for WinUI 3.) * Inter.ttf + JetBrainsMono.ttf + dragon-mark.png + teamsiso.ico copied from the WPF project's Assets/ so the WinUI 3 host is self-contained. * TeamsISO.sln + TeamsISO.Windows.slnf updated to include the new project. The .slnf paths switch to backslash form so MSBuild can match them against the .sln's canonical path representation. Verified: dotnet build TeamsISO.Windows.slnf -c Debug succeeds with 0 warnings and 0 errors for all 8 projects (WPF host, WinUI 3 host, engine, NDI interop, console, three test projects).
2026-05-12 23:52:35 -04:00
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="TeamsISO.App.WinUI.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
feat(winui3): redesigned MainWindow + custom title bar + theme toggle Lands the approved shape brief as the WinUI 3 MainWindow: * 64px left rail with brand mark, primary nav (participants), Teams launch / hide / settings buttons, and the engine-status puck at the bottom. All five rail buttons use Segoe Fluent Icons glyphs at a uniform 20px optical size; no more bespoke <Path Data> shapes with inconsistent stroke weights. * 44px custom title bar via ExtendsContentIntoTitleBar + SetTitleBar(AppTitleBar). The drag region absorbs the three live-state pills inline (session timer 'live * 00:14:32', REC count + elapsed, disk free) and a slim sun/moon theme-toggle button to the left of the system Min/Max/Close controls. System buttons inherit ButtonForeground Color etc. from AppWindow.TitleBar so they match palette in both themes. * Section header with 'Participants * count' display, filter input, Refresh + Presets (Secondary buttons), and 'Enable all online' as the single cyan Primary button - finally a real button hierarchy instead of seven indistinguishable ghost buttons. * Participants list rendered as ItemsRepeater + DataTemplate for now; the CommunityToolkit DataGrid migration follows in a separate commit. Row template at 64px height with: 3px cyan left border for active speaker, avatar with initials in cyan-muted circle, name + codec line, signal lock state with dot, audio meter via ProgressBar, output name in JetBrains Mono, ISO state pill (LIVE/OFF/ERROR) at right. * Conditional in-call control bar below the table: Mute / Camera / Share / Marker / Leave + overflow kebab. Muted state binds the destructive coral treatment to the Mute button; Leave is also destructive (coral border + text); everything else is Secondary. Tight 8px spacing keeps the bar dense without crowding. * Slim 32px status bar at the bottom: control-surface URL on the left (cyan dot indicator), keyboard-shortcut hints on the right in tertiary mono. Replaces the WPF host's six-column footer. Implementation notes: * MockParticipant model populates the table with representative data (Maya / Daniel / Aicha / Sam, one as active speaker) until the ParticipantViewModel binding migrates over from the WPF host. * Custom Program.cs takes ownership of Main from the XAML compiler (DISABLE_XAML_GENERATED_MAIN). Calls Bootstrap.TryInitialize(0x00010006) before Application.Start so the unpackaged .exe can locate the WindowsAppSDK 1.6 framework MSIX at launch. Shutdown is paired in a finally block. * Theme toggle in code-behind flips Window.Content.RequestedTheme between Dark and Light. {ThemeResource} bindings auto-swap across the visual tree; system title-bar buttons (outside the XAML tree) get color updates inline so they stay readable in both modes. * app.manifest deferred from build - the framework-emitted manifest covers DPI awareness and supportedOS GUIDs; reintroducing our own goes in the next commit alongside the bootstrapper hardening. Known issue: the unpackaged .exe currently fails to activate on this build host with 'this application could not be started' before Main runs. Build is clean; published output runs the same way. Diagnosing the activation failure is the next session's first task (likely the runtimeconfig.json including Microsoft.WindowsDesktop.App which WinUI 3 doesn't want, or a missing CRT redistributable). The WPF host remains the running build until that's resolved. dotnet build TeamsISO.Windows.slnf -c Debug: 0 warnings, 0 errors.
2026-05-13 00:03:12 -04:00
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:models="using:TeamsISO.App.WinUI.Models"
xmlns:views="using:TeamsISO.App.WinUI.Views">
feat(winui3): redesigned MainWindow + custom title bar + theme toggle Lands the approved shape brief as the WinUI 3 MainWindow: * 64px left rail with brand mark, primary nav (participants), Teams launch / hide / settings buttons, and the engine-status puck at the bottom. All five rail buttons use Segoe Fluent Icons glyphs at a uniform 20px optical size; no more bespoke <Path Data> shapes with inconsistent stroke weights. * 44px custom title bar via ExtendsContentIntoTitleBar + SetTitleBar(AppTitleBar). The drag region absorbs the three live-state pills inline (session timer 'live * 00:14:32', REC count + elapsed, disk free) and a slim sun/moon theme-toggle button to the left of the system Min/Max/Close controls. System buttons inherit ButtonForeground Color etc. from AppWindow.TitleBar so they match palette in both themes. * Section header with 'Participants * count' display, filter input, Refresh + Presets (Secondary buttons), and 'Enable all online' as the single cyan Primary button - finally a real button hierarchy instead of seven indistinguishable ghost buttons. * Participants list rendered as ItemsRepeater + DataTemplate for now; the CommunityToolkit DataGrid migration follows in a separate commit. Row template at 64px height with: 3px cyan left border for active speaker, avatar with initials in cyan-muted circle, name + codec line, signal lock state with dot, audio meter via ProgressBar, output name in JetBrains Mono, ISO state pill (LIVE/OFF/ERROR) at right. * Conditional in-call control bar below the table: Mute / Camera / Share / Marker / Leave + overflow kebab. Muted state binds the destructive coral treatment to the Mute button; Leave is also destructive (coral border + text); everything else is Secondary. Tight 8px spacing keeps the bar dense without crowding. * Slim 32px status bar at the bottom: control-surface URL on the left (cyan dot indicator), keyboard-shortcut hints on the right in tertiary mono. Replaces the WPF host's six-column footer. Implementation notes: * MockParticipant model populates the table with representative data (Maya / Daniel / Aicha / Sam, one as active speaker) until the ParticipantViewModel binding migrates over from the WPF host. * Custom Program.cs takes ownership of Main from the XAML compiler (DISABLE_XAML_GENERATED_MAIN). Calls Bootstrap.TryInitialize(0x00010006) before Application.Start so the unpackaged .exe can locate the WindowsAppSDK 1.6 framework MSIX at launch. Shutdown is paired in a finally block. * Theme toggle in code-behind flips Window.Content.RequestedTheme between Dark and Light. {ThemeResource} bindings auto-swap across the visual tree; system title-bar buttons (outside the XAML tree) get color updates inline so they stay readable in both modes. * app.manifest deferred from build - the framework-emitted manifest covers DPI awareness and supportedOS GUIDs; reintroducing our own goes in the next commit alongside the bootstrapper hardening. Known issue: the unpackaged .exe currently fails to activate on this build host with 'this application could not be started' before Main runs. Build is clean; published output runs the same way. Diagnosing the activation failure is the next session's first task (likely the runtimeconfig.json including Microsoft.WindowsDesktop.App which WinUI 3 doesn't want, or a missing CRT redistributable). The WPF host remains the running build until that's resolved. dotnet build TeamsISO.Windows.slnf -c Debug: 0 warnings, 0 errors.
2026-05-13 00:03:12 -04:00
<!--
TeamsISO MainWindow — redesigned IA per the approved shape brief.
Structure:
[64 rail] [content]
[44 title bar — drag region]
[section header]
[participants list — hero]
[in-call control — conditional]
[32 status bar]
The rail's bottom puck opens the engine-status popover that absorbs
what used to live in the WPF footer (logs path, version, control
surface URL details). The title bar absorbs the live state pills
(session timer · REC · disk free) so the operator's at-a-glance
read stays in peripheral vision regardless of scroll position.
Settings is a right-side drawer (opened from the rail settings icon)
rather than a permanent 380px panel — the participants list claims
the full content width when settings aren't being actively edited.
-->
feat(winui3): scaffold TeamsISO.App.WinUI alongside the WPF host First step of the WinUI 3 replatform per the approved redesign brief. The new project coexists with the existing src/TeamsISO.App (WPF) so the WPF host keeps building and shipping while the WinUI 3 redesign lands incrementally. Once the WinUI 3 build is feature-complete and tested against a real Teams meeting, the WPF project is retired. Scaffold contents: * src/TeamsISO.App.WinUI/TeamsISO.App.WinUI.csproj Windows App SDK 1.6 LTS (250602001), unpackaged mode (WindowsPackageType=None) so the existing MSI installer keeps working. Target framework net8.0-windows10.0.19041.0, min platform 10.0.17763.0 to preserve Win10 1809+ compatibility for working broadcast hardware. Pins WindowsSdkPackageVersion=10.0.19041.38 so .NET SDK 8.0.301 builds cleanly without an SDK upgrade on the build host. * src/TeamsISO.App.WinUI/app.manifest PerMonitorV2 DPI awareness + gdiScaling for crisp text on high-DPI broadcast monitors. asInvoker trust level (control surface :9755 and OSC :9000 bind to 127.0.0.1, no admin needed). * App.xaml + App.xaml.cs Minimal startup: brings up MainWindow. The full pipeline (NDI runtime preflight, IsoController wiring, single-instance mutex, REST + OSC bridge, tray icon, crash diagnostics, auto-update banner, onboarding) migrates in subsequent commits. * Themes/Tokens.xaml Wild Dragon design tokens as ThemeDictionary entries (Default = Dark, Light). Colors as Color resources, Brushes paired per theme so {ThemeResource} auto-swaps when RequestedTheme flips — no app restart, no flicker. Spacing/radii/typography tokens are theme-agnostic at the outer level. Light palette maintains brand recognition via cyan-tinted off-whites (#FAFAFB canvas, #F0F1F3 rail) rather than pure white, and splits cyan into accent.cyan.surface (#97EDF0, works in both modes because text on top is near-black) and accent.cyan.text (#97EDF0 dark / #0E7C82 light) so captions and inline labels keep AA contrast. * Themes/Controls.xaml Button hierarchy with real commitments: Primary (cyan fill, one per surface), Secondary (transparent bordered), Tertiary (text only), Destructive (coral border + text), Caption (titlebar), RailIcon. Typographic ramp (Display / Title / Heading / Body / Subtle / Caption / Mono) at the DESIGN.md 1.25 ratio. * CommunityToolkit.WinUI.UI.Controls.DataGrid 7.1.2 referenced for the participants table migration. (Toolkit 8.x dropped DataGrid; 7.x is the only currently-maintained free option for WinUI 3.) * Inter.ttf + JetBrainsMono.ttf + dragon-mark.png + teamsiso.ico copied from the WPF project's Assets/ so the WinUI 3 host is self-contained. * TeamsISO.sln + TeamsISO.Windows.slnf updated to include the new project. The .slnf paths switch to backslash form so MSBuild can match them against the .sln's canonical path representation. Verified: dotnet build TeamsISO.Windows.slnf -c Debug succeeds with 0 warnings and 0 errors for all 8 projects (WPF host, WinUI 3 host, engine, NDI interop, console, three test projects).
2026-05-12 23:52:35 -04:00
<Grid Background="{ThemeResource BgCanvas}">
feat(winui3): redesigned MainWindow + custom title bar + theme toggle Lands the approved shape brief as the WinUI 3 MainWindow: * 64px left rail with brand mark, primary nav (participants), Teams launch / hide / settings buttons, and the engine-status puck at the bottom. All five rail buttons use Segoe Fluent Icons glyphs at a uniform 20px optical size; no more bespoke <Path Data> shapes with inconsistent stroke weights. * 44px custom title bar via ExtendsContentIntoTitleBar + SetTitleBar(AppTitleBar). The drag region absorbs the three live-state pills inline (session timer 'live * 00:14:32', REC count + elapsed, disk free) and a slim sun/moon theme-toggle button to the left of the system Min/Max/Close controls. System buttons inherit ButtonForeground Color etc. from AppWindow.TitleBar so they match palette in both themes. * Section header with 'Participants * count' display, filter input, Refresh + Presets (Secondary buttons), and 'Enable all online' as the single cyan Primary button - finally a real button hierarchy instead of seven indistinguishable ghost buttons. * Participants list rendered as ItemsRepeater + DataTemplate for now; the CommunityToolkit DataGrid migration follows in a separate commit. Row template at 64px height with: 3px cyan left border for active speaker, avatar with initials in cyan-muted circle, name + codec line, signal lock state with dot, audio meter via ProgressBar, output name in JetBrains Mono, ISO state pill (LIVE/OFF/ERROR) at right. * Conditional in-call control bar below the table: Mute / Camera / Share / Marker / Leave + overflow kebab. Muted state binds the destructive coral treatment to the Mute button; Leave is also destructive (coral border + text); everything else is Secondary. Tight 8px spacing keeps the bar dense without crowding. * Slim 32px status bar at the bottom: control-surface URL on the left (cyan dot indicator), keyboard-shortcut hints on the right in tertiary mono. Replaces the WPF host's six-column footer. Implementation notes: * MockParticipant model populates the table with representative data (Maya / Daniel / Aicha / Sam, one as active speaker) until the ParticipantViewModel binding migrates over from the WPF host. * Custom Program.cs takes ownership of Main from the XAML compiler (DISABLE_XAML_GENERATED_MAIN). Calls Bootstrap.TryInitialize(0x00010006) before Application.Start so the unpackaged .exe can locate the WindowsAppSDK 1.6 framework MSIX at launch. Shutdown is paired in a finally block. * Theme toggle in code-behind flips Window.Content.RequestedTheme between Dark and Light. {ThemeResource} bindings auto-swap across the visual tree; system title-bar buttons (outside the XAML tree) get color updates inline so they stay readable in both modes. * app.manifest deferred from build - the framework-emitted manifest covers DPI awareness and supportedOS GUIDs; reintroducing our own goes in the next commit alongside the bootstrapper hardening. Known issue: the unpackaged .exe currently fails to activate on this build host with 'this application could not be started' before Main runs. Build is clean; published output runs the same way. Diagnosing the activation failure is the next session's first task (likely the runtimeconfig.json including Microsoft.WindowsDesktop.App which WinUI 3 doesn't want, or a missing CRT redistributable). The WPF host remains the running build until that's resolved. dotnet build TeamsISO.Windows.slnf -c Debug: 0 warnings, 0 errors.
2026-05-13 00:03:12 -04:00
<Grid.ColumnDefinitions>
<ColumnDefinition Width="64"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<!-- Drawer slide-in: 220ms ease-out-quart, translates 400px → 0 -->
<Storyboard x:Key="DrawerSlideIn">
<DoubleAnimation Storyboard.TargetName="DrawerTransform"
Storyboard.TargetProperty="X"
To="0"
Duration="0:0:0.22">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="DrawerSlideOut">
<DoubleAnimation Storyboard.TargetName="DrawerTransform"
Storyboard.TargetProperty="X"
To="400"
Duration="0:0:0.18">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
feat(winui3): redesigned MainWindow + custom title bar + theme toggle Lands the approved shape brief as the WinUI 3 MainWindow: * 64px left rail with brand mark, primary nav (participants), Teams launch / hide / settings buttons, and the engine-status puck at the bottom. All five rail buttons use Segoe Fluent Icons glyphs at a uniform 20px optical size; no more bespoke <Path Data> shapes with inconsistent stroke weights. * 44px custom title bar via ExtendsContentIntoTitleBar + SetTitleBar(AppTitleBar). The drag region absorbs the three live-state pills inline (session timer 'live * 00:14:32', REC count + elapsed, disk free) and a slim sun/moon theme-toggle button to the left of the system Min/Max/Close controls. System buttons inherit ButtonForeground Color etc. from AppWindow.TitleBar so they match palette in both themes. * Section header with 'Participants * count' display, filter input, Refresh + Presets (Secondary buttons), and 'Enable all online' as the single cyan Primary button - finally a real button hierarchy instead of seven indistinguishable ghost buttons. * Participants list rendered as ItemsRepeater + DataTemplate for now; the CommunityToolkit DataGrid migration follows in a separate commit. Row template at 64px height with: 3px cyan left border for active speaker, avatar with initials in cyan-muted circle, name + codec line, signal lock state with dot, audio meter via ProgressBar, output name in JetBrains Mono, ISO state pill (LIVE/OFF/ERROR) at right. * Conditional in-call control bar below the table: Mute / Camera / Share / Marker / Leave + overflow kebab. Muted state binds the destructive coral treatment to the Mute button; Leave is also destructive (coral border + text); everything else is Secondary. Tight 8px spacing keeps the bar dense without crowding. * Slim 32px status bar at the bottom: control-surface URL on the left (cyan dot indicator), keyboard-shortcut hints on the right in tertiary mono. Replaces the WPF host's six-column footer. Implementation notes: * MockParticipant model populates the table with representative data (Maya / Daniel / Aicha / Sam, one as active speaker) until the ParticipantViewModel binding migrates over from the WPF host. * Custom Program.cs takes ownership of Main from the XAML compiler (DISABLE_XAML_GENERATED_MAIN). Calls Bootstrap.TryInitialize(0x00010006) before Application.Start so the unpackaged .exe can locate the WindowsAppSDK 1.6 framework MSIX at launch. Shutdown is paired in a finally block. * Theme toggle in code-behind flips Window.Content.RequestedTheme between Dark and Light. {ThemeResource} bindings auto-swap across the visual tree; system title-bar buttons (outside the XAML tree) get color updates inline so they stay readable in both modes. * app.manifest deferred from build - the framework-emitted manifest covers DPI awareness and supportedOS GUIDs; reintroducing our own goes in the next commit alongside the bootstrapper hardening. Known issue: the unpackaged .exe currently fails to activate on this build host with 'this application could not be started' before Main runs. Build is clean; published output runs the same way. Diagnosing the activation failure is the next session's first task (likely the runtimeconfig.json including Microsoft.WindowsDesktop.App which WinUI 3 doesn't want, or a missing CRT redistributable). The WPF host remains the running build until that's resolved. dotnet build TeamsISO.Windows.slnf -c Debug: 0 warnings, 0 errors.
2026-05-13 00:03:12 -04:00
<!-- ═══════════════════════ LEFT RAIL ═══════════════════════ -->
<Border Grid.Column="0"
Background="{ThemeResource BgRail}"
BorderBrush="{ThemeResource BorderSubtle}"
BorderThickness="0,0,1,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Spacing="2" Padding="0,12,0,0">
<!-- Wild Dragon brand mark -->
<Button x:Name="BrandButton"
Style="{StaticResource ButtonRailIcon}"
Width="48" Height="56"
Margin="8,0,8,8"
ToolTipService.ToolTip="About TeamsISO">
<Border Width="40" Height="40"
CornerRadius="{ThemeResource RadiusM}"
Background="{ThemeResource AccentCyanMuted}">
<TextBlock Text="W"
FontFamily="{ThemeResource FontSans}"
FontSize="22"
FontWeight="Bold"
Foreground="{ThemeResource AccentCyanText}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</Button>
<Border Height="1"
Background="{ThemeResource BorderSubtle}"
Margin="14,4,14,12"/>
<!-- Participants / Home (active) -->
<Button Style="{StaticResource ButtonRailIcon}"
Margin="8,0"
ToolTipService.ToolTip="Participants">
<Grid>
<Border Width="48" Height="48"
CornerRadius="{ThemeResource RadiusM}"
Background="{ThemeResource AccentCyanMuted}"/>
<FontIcon Glyph="&#xE716;"
FontSize="20"
Foreground="{ThemeResource AccentCyanText}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Button>
<!-- Launch / surface Teams -->
<Button Style="{StaticResource ButtonRailIcon}"
Margin="8,0"
ToolTipService.ToolTip="Launch Microsoft Teams (or surface its window)">
<FontIcon Glyph="&#xE714;"
FontSize="20"
Foreground="{ThemeResource FgSecondary}"/>
</Button>
<!-- Hide / show Teams windows -->
<Button Style="{StaticResource ButtonRailIcon}"
Margin="8,0"
ToolTipService.ToolTip="Hide / show Microsoft Teams windows">
<FontIcon Glyph="&#xE7B3;"
FontSize="20"
Foreground="{ThemeResource FgSecondary}"/>
</Button>
<!-- Settings drawer trigger -->
<Button x:Name="SettingsButton"
Style="{StaticResource ButtonRailIcon}"
Margin="8,0"
Click="OnSettingsClick"
feat(winui3): redesigned MainWindow + custom title bar + theme toggle Lands the approved shape brief as the WinUI 3 MainWindow: * 64px left rail with brand mark, primary nav (participants), Teams launch / hide / settings buttons, and the engine-status puck at the bottom. All five rail buttons use Segoe Fluent Icons glyphs at a uniform 20px optical size; no more bespoke <Path Data> shapes with inconsistent stroke weights. * 44px custom title bar via ExtendsContentIntoTitleBar + SetTitleBar(AppTitleBar). The drag region absorbs the three live-state pills inline (session timer 'live * 00:14:32', REC count + elapsed, disk free) and a slim sun/moon theme-toggle button to the left of the system Min/Max/Close controls. System buttons inherit ButtonForeground Color etc. from AppWindow.TitleBar so they match palette in both themes. * Section header with 'Participants * count' display, filter input, Refresh + Presets (Secondary buttons), and 'Enable all online' as the single cyan Primary button - finally a real button hierarchy instead of seven indistinguishable ghost buttons. * Participants list rendered as ItemsRepeater + DataTemplate for now; the CommunityToolkit DataGrid migration follows in a separate commit. Row template at 64px height with: 3px cyan left border for active speaker, avatar with initials in cyan-muted circle, name + codec line, signal lock state with dot, audio meter via ProgressBar, output name in JetBrains Mono, ISO state pill (LIVE/OFF/ERROR) at right. * Conditional in-call control bar below the table: Mute / Camera / Share / Marker / Leave + overflow kebab. Muted state binds the destructive coral treatment to the Mute button; Leave is also destructive (coral border + text); everything else is Secondary. Tight 8px spacing keeps the bar dense without crowding. * Slim 32px status bar at the bottom: control-surface URL on the left (cyan dot indicator), keyboard-shortcut hints on the right in tertiary mono. Replaces the WPF host's six-column footer. Implementation notes: * MockParticipant model populates the table with representative data (Maya / Daniel / Aicha / Sam, one as active speaker) until the ParticipantViewModel binding migrates over from the WPF host. * Custom Program.cs takes ownership of Main from the XAML compiler (DISABLE_XAML_GENERATED_MAIN). Calls Bootstrap.TryInitialize(0x00010006) before Application.Start so the unpackaged .exe can locate the WindowsAppSDK 1.6 framework MSIX at launch. Shutdown is paired in a finally block. * Theme toggle in code-behind flips Window.Content.RequestedTheme between Dark and Light. {ThemeResource} bindings auto-swap across the visual tree; system title-bar buttons (outside the XAML tree) get color updates inline so they stay readable in both modes. * app.manifest deferred from build - the framework-emitted manifest covers DPI awareness and supportedOS GUIDs; reintroducing our own goes in the next commit alongside the bootstrapper hardening. Known issue: the unpackaged .exe currently fails to activate on this build host with 'this application could not be started' before Main runs. Build is clean; published output runs the same way. Diagnosing the activation failure is the next session's first task (likely the runtimeconfig.json including Microsoft.WindowsDesktop.App which WinUI 3 doesn't want, or a missing CRT redistributable). The WPF host remains the running build until that's resolved. dotnet build TeamsISO.Windows.slnf -c Debug: 0 warnings, 0 errors.
2026-05-13 00:03:12 -04:00
ToolTipService.ToolTip="Settings">
<FontIcon Glyph="&#xE713;"
FontSize="20"
Foreground="{ThemeResource FgSecondary}"/>
</Button>
</StackPanel>
<!-- Engine status puck — opens the status popover -->
<Button x:Name="StatusPuckButton"
Grid.Row="1"
Style="{StaticResource ButtonRailIcon}"
Width="48" Height="48"
Margin="8,12"
CornerRadius="24"
Background="{ThemeResource StatusLiveBg}"
ToolTipService.ToolTip="Engine status">
<Ellipse Width="10" Height="10"
Fill="{ThemeResource StatusLive}"/>
</Button>
</Grid>
</Border>
<!-- ═══════════════════════ CONTENT ═══════════════════════ -->
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="44"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="32"/>
</Grid.RowDefinitions>
<!-- ─── Title bar ─── -->
<!--
AppTitleBar is the drag region. Window.SetTitleBar(AppTitleBar)
in code-behind makes this element the operating-system-defined
drag area. The system Min/Max/Close buttons render to the right
of this element automatically (their colors come from
AppWindow.TitleBar.ButtonForegroundColor etc.); we draw
everything else.
-->
<Grid x:Name="AppTitleBar"
Grid.Row="0"
Background="{ThemeResource BgCanvas}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal"
Spacing="12"
Padding="24,0,0,0"
VerticalAlignment="Center">
<TextBlock Text="TeamsISO"
Style="{StaticResource TextHeading}"
VerticalAlignment="Center"/>
<TextBlock x:Name="VersionLabel"
Text="v1.0.0-alpha"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource FgTertiary}"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Live pills (session timer / REC count / disk) live in the
title bar so peripheral-vision status reads from the same
place whether the operator is scrolled, settings-drawer
open, or in-call. Conditionally shown via code-behind. -->
<StackPanel x:Name="LivePillsPanel"
Grid.Column="2"
Orientation="Horizontal"
Spacing="8"
VerticalAlignment="Center"
Padding="0,0,12,0">
<Border CornerRadius="{ThemeResource RadiusPill}"
Background="{ThemeResource StatusLiveBg}"
Padding="10,4">
<StackPanel Orientation="Horizontal" Spacing="6">
<Ellipse Width="7" Height="7"
Fill="{ThemeResource StatusLive}"
VerticalAlignment="Center"/>
<TextBlock x:Name="SessionTimerText"
Text="live · 00:14:32"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource StatusLive}"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
<Border CornerRadius="{ThemeResource RadiusPill}"
Background="{ThemeResource AccentCoralBg}"
Padding="10,4">
<StackPanel Orientation="Horizontal" Spacing="6">
<Ellipse Width="7" Height="7"
Fill="{ThemeResource AccentCoral}"
VerticalAlignment="Center"/>
<TextBlock x:Name="RecPillText"
Text="rec 3 · 00:11:08"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource AccentCoral}"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
<Border CornerRadius="{ThemeResource RadiusPill}"
Background="{ThemeResource BgSurface}"
BorderBrush="{ThemeResource BorderSubtle}"
BorderThickness="1"
Padding="10,4">
<TextBlock x:Name="DiskFreeText"
Text="482 GB free"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource FgSecondary}"
VerticalAlignment="Center"/>
</Border>
</StackPanel>
<!-- Theme toggle — single-click cycle between Dark and Light.
Persisted to UIPreferences.Theme on click. -->
<Button x:Name="ThemeToggleButton"
Grid.Column="3"
Style="{StaticResource ButtonCaption}"
Click="OnThemeToggleClick"
ToolTipService.ToolTip="Toggle theme (dark / light)">
<FontIcon x:Name="ThemeToggleIcon"
Glyph="&#xE706;"
FontSize="14"/>
</Button>
<!-- The Min / Max / Close buttons that follow in Grid.Column 4,5
are NOT drawn here — the WindowsAppSDK title-bar API draws
them itself, overlaid on the drag region we've defined.
The reserved columns 4 and 5 are just visual placeholders
in this layout to remind future readers where they land. -->
<Border Grid.Column="4" Width="138" Background="Transparent"/>
</Grid>
<!-- ─── Section header ─── -->
<Grid Grid.Row="1" Padding="32,18,32,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal"
Spacing="12"
VerticalAlignment="Center">
<TextBlock Text="Participants"
Style="{StaticResource TextDisplay}"/>
<Border CornerRadius="{ThemeResource RadiusPill}"
Background="{ThemeResource BgSurface}"
BorderBrush="{ThemeResource BorderSubtle}"
BorderThickness="1"
Padding="10,3"
VerticalAlignment="Center">
<TextBlock x:Name="ParticipantCountText"
Text="4"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource FgSecondary}"/>
</Border>
</StackPanel>
<StackPanel Grid.Column="2"
Orientation="Horizontal"
Spacing="8"
VerticalAlignment="Center">
<TextBox x:Name="FilterInput"
PlaceholderText="Filter"
Width="200"
VerticalAlignment="Center"/>
<Button Style="{StaticResource ButtonSecondary}"
Content="Refresh"
ToolTipService.ToolTip="Refresh NDI discovery"/>
<Button Style="{StaticResource ButtonSecondary}"
Content="Presets"
ToolTipService.ToolTip="Save or load operator presets"/>
<Button Style="{StaticResource ButtonPrimary}"
Content="Enable all online"
HorizontalAlignment="Right"
ToolTipService.ToolTip="Enable ISOs for every online participant"/>
</StackPanel>
</Grid>
<!-- ─── Participants list (hero) ─── -->
<ScrollViewer Grid.Row="2"
Padding="32,0,32,0"
VerticalScrollBarVisibility="Auto">
<ItemsRepeater x:Name="ParticipantsRepeater">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical" Spacing="0"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="models:MockParticipant">
<Grid Height="64"
Padding="0,0,12,0"
BorderBrush="{ThemeResource BorderSubtle}"
BorderThickness="0,0,0,1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1.2*"/>
<ColumnDefinition Width="1.5*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
Width="3" Height="64"
Background="{ThemeResource AccentCyanText}"
Visibility="{Binding IsActiveSpeaker}"/>
<StackPanel Grid.Column="1"
Orientation="Horizontal"
Spacing="12"
Padding="14,0,0,0"
VerticalAlignment="Center">
<Border Width="36" Height="36"
CornerRadius="18"
Background="{ThemeResource AccentCyanMuted}">
<TextBlock Text="{Binding Initials}"
Style="{StaticResource TextBody}"
FontWeight="SemiBold"
Foreground="{ThemeResource AccentCyanText}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<StackPanel VerticalAlignment="Center" Spacing="2">
<TextBlock Text="{Binding DisplayName}"
Style="{StaticResource TextBody}"
FontWeight="Medium"/>
<TextBlock Text="{Binding SourceCodec}"
Style="{StaticResource TextCaption}"
Foreground="{ThemeResource FgSecondary}"/>
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="2"
Orientation="Horizontal"
Spacing="8"
VerticalAlignment="Center">
<Ellipse Width="8" Height="8"
Fill="{ThemeResource StatusLive}"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding SignalState}"
Style="{StaticResource TextMono}"
FontSize="11"/>
</StackPanel>
<Grid Grid.Column="3" VerticalAlignment="Center" Height="22">
<ProgressBar Maximum="1.0"
Value="{Binding AudioLevel}"
Height="6"
VerticalAlignment="Center"/>
</Grid>
<TextBlock Grid.Column="4"
Text="{Binding OutputName}"
Style="{StaticResource TextMono}"
VerticalAlignment="Center"/>
<Border Grid.Column="5"
CornerRadius="{ThemeResource RadiusPill}"
Background="{ThemeResource StatusLiveBg}"
BorderBrush="{ThemeResource StatusLive}"
BorderThickness="1"
Padding="14,6"
MinWidth="80"
VerticalAlignment="Center">
<TextBlock Text="{Binding IsoState}"
Style="{StaticResource TextBody}"
FontSize="11"
FontWeight="SemiBold"
Foreground="{ThemeResource StatusLive}"
HorizontalAlignment="Center"/>
</Border>
</Grid>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
<!-- ─── In-call control (conditional) ─── -->
<Border Grid.Row="3"
Padding="32,12,32,12"
BorderBrush="{ThemeResource BorderSubtle}"
BorderThickness="0,1,0,0"
Background="{ThemeResource BgCanvas}">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="IN-CALL"
Style="{StaticResource TextCaption}"
VerticalAlignment="Center"
Margin="0,0,8,0"/>
<Button Style="{StaticResource ButtonDestructive}"
ToolTipService.ToolTip="Toggle microphone mute">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon Glyph="&#xE74F;" FontSize="14"/>
<TextBlock Text="Muted"/>
</StackPanel>
</Button>
<Button Style="{StaticResource ButtonSecondary}"
ToolTipService.ToolTip="Toggle camera">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon Glyph="&#xE714;" FontSize="14"/>
<TextBlock Text="Camera"/>
</StackPanel>
</Button>
<Button Style="{StaticResource ButtonSecondary}"
ToolTipService.ToolTip="Open Teams share tray">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon Glyph="&#xE72D;" FontSize="14"/>
<TextBlock Text="Share"/>
</StackPanel>
</Button>
<Button Style="{StaticResource ButtonSecondary}"
ToolTipService.ToolTip="Drop a timestamped marker into every active recording">
<StackPanel Orientation="Horizontal" Spacing="6">
<FontIcon Glyph="&#xE735;" FontSize="14"/>
<TextBlock Text="Marker"/>
</StackPanel>
</Button>
<Button Style="{StaticResource ButtonDestructive}"
ToolTipService.ToolTip="Leave the Teams call">
<TextBlock Text="Leave"/>
</Button>
</StackPanel>
</Border>
<!-- ─── Settings drawer (slides over rows 1-3) ─── -->
<views:SettingsDrawer x:Name="SettingsDrawerHost"
Grid.Row="0"
Grid.RowSpan="4"
HorizontalAlignment="Right"
Width="400"
IsHitTestVisible="False">
<views:SettingsDrawer.RenderTransform>
<TranslateTransform x:Name="DrawerTransform" X="400"/>
</views:SettingsDrawer.RenderTransform>
</views:SettingsDrawer>
feat(winui3): redesigned MainWindow + custom title bar + theme toggle Lands the approved shape brief as the WinUI 3 MainWindow: * 64px left rail with brand mark, primary nav (participants), Teams launch / hide / settings buttons, and the engine-status puck at the bottom. All five rail buttons use Segoe Fluent Icons glyphs at a uniform 20px optical size; no more bespoke <Path Data> shapes with inconsistent stroke weights. * 44px custom title bar via ExtendsContentIntoTitleBar + SetTitleBar(AppTitleBar). The drag region absorbs the three live-state pills inline (session timer 'live * 00:14:32', REC count + elapsed, disk free) and a slim sun/moon theme-toggle button to the left of the system Min/Max/Close controls. System buttons inherit ButtonForeground Color etc. from AppWindow.TitleBar so they match palette in both themes. * Section header with 'Participants * count' display, filter input, Refresh + Presets (Secondary buttons), and 'Enable all online' as the single cyan Primary button - finally a real button hierarchy instead of seven indistinguishable ghost buttons. * Participants list rendered as ItemsRepeater + DataTemplate for now; the CommunityToolkit DataGrid migration follows in a separate commit. Row template at 64px height with: 3px cyan left border for active speaker, avatar with initials in cyan-muted circle, name + codec line, signal lock state with dot, audio meter via ProgressBar, output name in JetBrains Mono, ISO state pill (LIVE/OFF/ERROR) at right. * Conditional in-call control bar below the table: Mute / Camera / Share / Marker / Leave + overflow kebab. Muted state binds the destructive coral treatment to the Mute button; Leave is also destructive (coral border + text); everything else is Secondary. Tight 8px spacing keeps the bar dense without crowding. * Slim 32px status bar at the bottom: control-surface URL on the left (cyan dot indicator), keyboard-shortcut hints on the right in tertiary mono. Replaces the WPF host's six-column footer. Implementation notes: * MockParticipant model populates the table with representative data (Maya / Daniel / Aicha / Sam, one as active speaker) until the ParticipantViewModel binding migrates over from the WPF host. * Custom Program.cs takes ownership of Main from the XAML compiler (DISABLE_XAML_GENERATED_MAIN). Calls Bootstrap.TryInitialize(0x00010006) before Application.Start so the unpackaged .exe can locate the WindowsAppSDK 1.6 framework MSIX at launch. Shutdown is paired in a finally block. * Theme toggle in code-behind flips Window.Content.RequestedTheme between Dark and Light. {ThemeResource} bindings auto-swap across the visual tree; system title-bar buttons (outside the XAML tree) get color updates inline so they stay readable in both modes. * app.manifest deferred from build - the framework-emitted manifest covers DPI awareness and supportedOS GUIDs; reintroducing our own goes in the next commit alongside the bootstrapper hardening. Known issue: the unpackaged .exe currently fails to activate on this build host with 'this application could not be started' before Main runs. Build is clean; published output runs the same way. Diagnosing the activation failure is the next session's first task (likely the runtimeconfig.json including Microsoft.WindowsDesktop.App which WinUI 3 doesn't want, or a missing CRT redistributable). The WPF host remains the running build until that's resolved. dotnet build TeamsISO.Windows.slnf -c Debug: 0 warnings, 0 errors.
2026-05-13 00:03:12 -04:00
<!-- ─── Status bar ─── -->
<Grid Grid.Row="4"
Padding="32,8,32,8"
Background="{ThemeResource BgCanvas}"
BorderBrush="{ThemeResource BorderSubtle}"
BorderThickness="0,1,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal"
Spacing="8"
VerticalAlignment="Center">
<Ellipse Width="6" Height="6"
Fill="{ThemeResource AccentCyanText}"
VerticalAlignment="Center"/>
<TextBlock Text="control surface · 127.0.0.1:9755"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource FgSecondary}"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Grid.Column="2"
Text="F1 help · Ctrl+M marker · Ctrl+Shift+S panic stop · Ctrl+K command palette"
Style="{StaticResource TextMono}"
FontSize="11"
Foreground="{ThemeResource FgTertiary}"
VerticalAlignment="Center"/>
</Grid>
</Grid>
feat(winui3): scaffold TeamsISO.App.WinUI alongside the WPF host First step of the WinUI 3 replatform per the approved redesign brief. The new project coexists with the existing src/TeamsISO.App (WPF) so the WPF host keeps building and shipping while the WinUI 3 redesign lands incrementally. Once the WinUI 3 build is feature-complete and tested against a real Teams meeting, the WPF project is retired. Scaffold contents: * src/TeamsISO.App.WinUI/TeamsISO.App.WinUI.csproj Windows App SDK 1.6 LTS (250602001), unpackaged mode (WindowsPackageType=None) so the existing MSI installer keeps working. Target framework net8.0-windows10.0.19041.0, min platform 10.0.17763.0 to preserve Win10 1809+ compatibility for working broadcast hardware. Pins WindowsSdkPackageVersion=10.0.19041.38 so .NET SDK 8.0.301 builds cleanly without an SDK upgrade on the build host. * src/TeamsISO.App.WinUI/app.manifest PerMonitorV2 DPI awareness + gdiScaling for crisp text on high-DPI broadcast monitors. asInvoker trust level (control surface :9755 and OSC :9000 bind to 127.0.0.1, no admin needed). * App.xaml + App.xaml.cs Minimal startup: brings up MainWindow. The full pipeline (NDI runtime preflight, IsoController wiring, single-instance mutex, REST + OSC bridge, tray icon, crash diagnostics, auto-update banner, onboarding) migrates in subsequent commits. * Themes/Tokens.xaml Wild Dragon design tokens as ThemeDictionary entries (Default = Dark, Light). Colors as Color resources, Brushes paired per theme so {ThemeResource} auto-swaps when RequestedTheme flips — no app restart, no flicker. Spacing/radii/typography tokens are theme-agnostic at the outer level. Light palette maintains brand recognition via cyan-tinted off-whites (#FAFAFB canvas, #F0F1F3 rail) rather than pure white, and splits cyan into accent.cyan.surface (#97EDF0, works in both modes because text on top is near-black) and accent.cyan.text (#97EDF0 dark / #0E7C82 light) so captions and inline labels keep AA contrast. * Themes/Controls.xaml Button hierarchy with real commitments: Primary (cyan fill, one per surface), Secondary (transparent bordered), Tertiary (text only), Destructive (coral border + text), Caption (titlebar), RailIcon. Typographic ramp (Display / Title / Heading / Body / Subtle / Caption / Mono) at the DESIGN.md 1.25 ratio. * CommunityToolkit.WinUI.UI.Controls.DataGrid 7.1.2 referenced for the participants table migration. (Toolkit 8.x dropped DataGrid; 7.x is the only currently-maintained free option for WinUI 3.) * Inter.ttf + JetBrainsMono.ttf + dragon-mark.png + teamsiso.ico copied from the WPF project's Assets/ so the WinUI 3 host is self-contained. * TeamsISO.sln + TeamsISO.Windows.slnf updated to include the new project. The .slnf paths switch to backslash form so MSBuild can match them against the .sln's canonical path representation. Verified: dotnet build TeamsISO.Windows.slnf -c Debug succeeds with 0 warnings and 0 errors for all 8 projects (WPF host, WinUI 3 host, engine, NDI interop, console, three test projects).
2026-05-12 23:52:35 -04:00
</Grid>
</Window>