Builds out the secondary surfaces of the redesigned WinUI 3 host.
ThemeManager (Services/ThemeManager.cs)
Single-source-of-truth for the active theme. Holds the user preference
(System / Dark / Light), resolves it to ElementTheme at request, and
raises a Themed event when it changes so the MainWindow can push the
AppWindow title-bar button colors. Uses Windows.UI.ViewManagement
UISettings to follow the OS app-mode when preference is System.
Persistence to UIPreferences lands in the engine-wiring commit.
MainWindow theme wiring
Replaces the per-handler theme toggle with a ThemeManager subscription:
click the title-bar sun/moon -> Toggle() -> Themed event ->
ApplyResolvedTheme on the visual tree + the title-bar buttons. Glyph
cue: sun = "current is Light, click to Dark"; moon = "current is Dark,
click to Light." Initial state applied at construction so the first
frame matches the preference.
SettingsDrawer (Views/SettingsDrawer.xaml + .cs)
UserControl that slides in from the right over the participants table.
56px header, NavigationView with five tabs (Appearance, Routing,
Display, Control, Advanced), footer with Reset-to-defaults +
Apply/Close. Appearance tab has the theme tri-state picker (System /
Dark / Light radio group) and an "Accent peek" row showing the four
brand accents (cyan / coral / live / warn) as swatches so the
operator can verify Wild Dragon brand is respected on a light desk.
CloseRequested event signals the host to collapse the drawer.
HelpDialog (Views/HelpDialog.xaml + .cs)
ContentDialog with the keyboard shortcut cheat sheet, grouped by
category (Global / Participants / Look / Control surface). 540px max
height with scroll, mono-spaced shortcut labels at left, body text at
right. Replaces the WPF host's HelpWindow at parity.
AboutDialog (Views/AboutDialog.xaml + .cs)
ContentDialog with the Wild Dragon mark, version + host + engine +
brand info as label/value rows, and three quick action buttons
(open logs folder, open recordings, check for updates). Mirrors the
WPF host's AboutWindow.
OnboardingDialog (Views/OnboardingDialog.xaml + .cs)
Three numbered steps (Install NDI Runtime / Enable Teams NDI / Pick
transcoder topology), no carousel, operator-tone copy ("Don't show
this again" defaults checked). PrimaryButtonText "Get started",
SecondaryButtonText "Skip" so the dialog is skippable from the first
frame as the PRODUCT.md anti-references demand.
Build clean: dotnet build TeamsISO.App.WinUI -c Debug -> 0 / 0.
Next: wire the drawer's CloseRequested into MainWindow (so the settings
icon actually opens / collapses the drawer), then attack the runtime
activation blocker (Phase 3 of the migration plan).
86 lines
4 KiB
C#
86 lines
4 KiB
C#
using Microsoft.UI;
|
|
using Microsoft.UI.Windowing;
|
|
using Microsoft.UI.Xaml;
|
|
using TeamsISO.App.WinUI.Models;
|
|
using TeamsISO.App.WinUI.Services;
|
|
using Windows.Graphics;
|
|
using Windows.UI;
|
|
|
|
namespace TeamsISO.App.WinUI.Views;
|
|
|
|
public sealed partial class MainWindow : Window
|
|
{
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
|
|
Title = "TeamsISO";
|
|
|
|
// ── Custom title bar wiring ───────────────────────────────────────
|
|
// ExtendsContentIntoTitleBar=true tells WindowsAppSDK to draw the
|
|
// window chrome over our content instead of reserving a Windows-default
|
|
// caption strip. SetTitleBar marks AppTitleBar as the drag region —
|
|
// clicks on it route to the system drag handler, everything else stays
|
|
// hit-testable as a normal XAML element. The system min/max/close
|
|
// buttons render on top of the right edge regardless; we just provide
|
|
// their colors so they match our palette.
|
|
ExtendsContentIntoTitleBar = true;
|
|
SetTitleBar(AppTitleBar);
|
|
|
|
AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
|
|
AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
|
AppWindow.TitleBar.ButtonHoverForegroundColor = Colors.White;
|
|
|
|
// ── Initial size & position ───────────────────────────────────────
|
|
// 1280x780 matches the WPF host's default — fits comfortably on a
|
|
// 14-inch laptop while giving the participants table 600+ pixels
|
|
// of vertical breathing room.
|
|
AppWindow.Resize(new SizeInt32(1280, 780));
|
|
|
|
// ── Mock data wiring (interim) ────────────────────────────────────
|
|
// Until ParticipantViewModel binds in the engine wiring commit, the
|
|
// table is populated from a static sample list so the visual design
|
|
// can be validated end-to-end against representative data.
|
|
ParticipantsRepeater.ItemsSource = MockParticipant.Sample();
|
|
|
|
// ── Theme system ──────────────────────────────────────────────────
|
|
// Subscribe to ThemeManager so picker changes from anywhere
|
|
// (settings drawer, title-bar toggle, system color change) reach
|
|
// the title-bar buttons and the visual tree consistently. Apply
|
|
// once at construction so the initial state matches the preference
|
|
// before the first frame.
|
|
ThemeManager.Current.Themed += (_, theme) => ApplyResolvedTheme(theme);
|
|
ApplyResolvedTheme(ThemeManager.Current.ResolveTheme());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cycle the active theme between Dark and Light from the title-bar
|
|
/// toggle. The actual swap lives in <see cref="ThemeManager"/>; this
|
|
/// handler just calls Toggle() and lets the subscription propagate.
|
|
/// </summary>
|
|
private void OnThemeToggleClick(object sender, RoutedEventArgs e)
|
|
{
|
|
ThemeManager.Current.Toggle();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Push a resolved theme to the visual tree and to the AppWindow
|
|
/// title-bar buttons. Called on every <see cref="ThemeManager.Themed"/>
|
|
/// event and once at construction.
|
|
/// </summary>
|
|
private void ApplyResolvedTheme(ElementTheme theme)
|
|
{
|
|
if (Content is FrameworkElement root)
|
|
{
|
|
root.RequestedTheme = theme;
|
|
}
|
|
|
|
AppWindow.TitleBar.ButtonForegroundColor = ThemeManager.TitleBarForegroundFor(theme);
|
|
AppWindow.TitleBar.ButtonHoverBackgroundColor = ThemeManager.TitleBarHoverBgFor(theme);
|
|
AppWindow.TitleBar.ButtonPressedBackgroundColor = ThemeManager.TitleBarHoverBgFor(theme);
|
|
|
|
// Glyph cue: sun () means current is Light, click moves to Dark;
|
|
// moon () means current is Dark, click moves to Light.
|
|
ThemeToggleIcon.Glyph = theme == ElementTheme.Light ? "" : "";
|
|
}
|
|
}
|