using System.Linq; using System.Windows; using System.Windows.Shapes; using TeamsISO.App.Services; using TeamsISO.App.ViewModels; namespace TeamsISO.App; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); StateChanged += OnWindowStateChanged; SourceInitialized += OnSourceInitialized; Closing += OnClosing; } public MainWindow(MainViewModel viewModel) : this() { DataContext = viewModel; } /// /// Restore the window's previous placement after the HWND is created (so /// SetWindowPos / WindowState transitions actually take effect). Falls /// silently back to the XAML-default startup location if no snapshot exists. /// private void OnSourceInitialized(object? sender, EventArgs e) { WindowStateStore.TryApply(this); } /// Persist the placement on close so next launch lands in the same spot. private void OnClosing(object? sender, System.ComponentModel.CancelEventArgs e) { WindowStateStore.Save(this); } /// Custom min button — chrome'd window has no system caption buttons. private void OnMinimize(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized; /// Toggles maximize/restore. Bound to the maximize button + double-click on the drag region. private void OnMaximizeRestore(object sender, RoutedEventArgs e) => WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; /// Custom close button. private void OnClose(object sender, RoutedEventArgs e) => Close(); /// Opens the About dialog — version, NDI runtime, build SHA. private void OnAboutClick(object sender, RoutedEventArgs e) { var about = new AboutWindow { Owner = this }; about.ShowDialog(); } /// /// Opens the operator-presets dialog. Hands it the current participants /// snapshot (so Save captures live state) and the engine controller (so /// Apply can reconcile enable/disable). Owner is set so the chromeless /// dialog centers over the main window and inherits z-order. /// private void OnPresetsClick(object sender, RoutedEventArgs e) { if (DataContext is not MainViewModel vm) return; var dialog = new PresetsDialog(vm.Controller, vm.Participants.ToList(), vm.Toast) { Owner = this, }; dialog.ShowDialog(); } /// /// Tracks whether we have hidden Teams' windows so the next click reverses /// the action. We treat this as "intent" rather than a query of OS state /// because hidden windows still report as hidden if the operator manually /// re-opens them and we only care about TeamsISO's own toggle history. /// private bool _teamsWindowsHidden; /// /// Phase E.2 toggle. Hides every visible top-level Teams window on first /// click; shows them again on the next. Surfaces the result via the toast /// so the operator gets feedback even though the affected windows aren't /// visible anymore. /// private void OnToggleTeamsWindowClick(object sender, RoutedEventArgs e) { if (!TeamsLauncher.IsRunning()) { MessageBox.Show( "Microsoft Teams isn't running. Click the camera icon above to launch it first.", "TeamsISO — Hide / show Teams", MessageBoxButton.OK, MessageBoxImage.Information); return; } var toast = (DataContext as MainViewModel)?.Toast; if (_teamsWindowsHidden) { var shown = TeamsLauncher.ShowWindows(); _teamsWindowsHidden = false; toast?.Show(shown > 0 ? $"Restored {shown} Teams window(s)" : "No Teams windows to restore"); } else { var hidden = TeamsLauncher.HideWindows(); _teamsWindowsHidden = hidden > 0; toast?.Show(hidden > 0 ? $"Hid {hidden} Teams window(s)" : "Teams has no visible windows yet"); } } /// /// Toggle behavior: if Teams is already running, ask to stop it; otherwise /// launch via TeamsLauncher's fallback chain. First step toward the /// Embedded-Teams roadmap (Phase E.1). /// private void OnLaunchTeamsClick(object sender, RoutedEventArgs e) { if (TeamsLauncher.IsRunning()) { var confirm = MessageBox.Show( "Microsoft Teams is currently running.\n\nClose all Teams windows now?", "TeamsISO — Stop Teams", MessageBoxButton.YesNo, MessageBoxImage.Question); if (confirm != MessageBoxResult.Yes) return; var asked = TeamsLauncher.StopAll(); if (TeamsLauncher.IsRunning()) { MessageBox.Show( asked == 0 ? "No Teams windows responded to close." : $"Sent close to {asked} Teams window(s); some may still be exiting.", "TeamsISO — Stop Teams", MessageBoxButton.OK, MessageBoxImage.Information); } return; } if (!TeamsLauncher.TryLaunch(out var error)) { MessageBox.Show( $"Could not launch Microsoft Teams.\n\n{error}", "TeamsISO — Launch Teams", MessageBoxButton.OK, MessageBoxImage.Warning); } } /// /// Swap the maximize-button glyph between the "single rectangle" (when normal) and the /// "two-overlapping-rectangles" (when maximized) variants, matching the Windows 11 /// caption-button conventions. /// private void OnWindowStateChanged(object? sender, EventArgs e) { if (FindName("MaximizeIcon") is not Path icon) return; icon.Data = WindowState == WindowState.Maximized // Two-rectangle "restore" glyph ? System.Windows.Media.Geometry.Parse("M 2,0 L 10,0 L 10,8 M 0,2 L 8,2 L 8,10 L 0,10 Z") // Single-rectangle "maximize" glyph : System.Windows.Media.Geometry.Parse("M 0,0 L 10,0 L 10,10 L 0,10 Z"); } }