using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.Versioning; using System.Windows; using System.Windows.Navigation; using TeamsISO.App.Services; using TeamsISO.Engine.NdiInterop; namespace TeamsISO.App; /// /// Modal "About" dialog. Surfaces enough info that a user filing a support ticket /// can paste version + NDI runtime + OS in a single screenshot. /// public partial class AboutWindow : Window { public AboutWindow() { InitializeComponent(); PopulateText(); } private void PopulateText() { var asm = typeof(App).Assembly; var info = asm.GetCustomAttribute()?.InformationalVersion ?? asm.GetName().Version?.ToString() ?? "unknown"; VersionText.Text = info; RuntimeText.Text = $".NET {Environment.Version}"; OsText.Text = Environment.OSVersion.ToString(); NdiText.Text = TryGetNdiVersion(); } [SupportedOSPlatform("windows")] private static string TryGetNdiVersion() { try { using var interop = new NdiInteropPInvoke( Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance); return interop.GetRuntimeVersion(); } catch (Exception ex) { return $"not initialized ({ex.Message})"; } } private void OnClose(object sender, RoutedEventArgs e) => Close(); /// /// Re-open the first-launch welcome dialog from About so users can revisit /// the setup checklist without having to delete the suppression flag file /// by hand. The "Don't show again" checkbox in the welcome dialog defaults /// to checked so a re-shown welcome won't unset the suppression on close. /// private void OnShowOnboarding(object sender, RoutedEventArgs e) { var onboarding = new OnboardingWindow { Owner = this }; onboarding.ShowDialog(); } /// /// Quick-jump: open a path in Explorer. Creates the directory if missing /// (operator might click "Recordings" before any have been made). Best- /// effort — Explorer launch failures don't surface a dialog. /// private static void OpenInExplorer(string path) { try { if (!Directory.Exists(path)) Directory.CreateDirectory(path); Process.Start(new ProcessStartInfo { FileName = path, UseShellExecute = true, }); } catch { // No-op: shell launch failed (path inaccessible / Explorer crashed) } } private void OnOpenLogs(object sender, RoutedEventArgs e) => OpenInExplorer(Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamsISO", "Logs")); // OnOpenRecordings removed — recording feature axed. private void OnOpenNotes(object sender, RoutedEventArgs e) => OpenInExplorer(Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TeamsISO", "Notes")); /// /// Build the diagnostic bundle and tell the operator where it landed. The /// bundle is just zipped logs / config / presets — no screenshots, no /// memory dumps. Intended to be attached to a bug report. /// private void OnExportDiagnostics(object sender, RoutedEventArgs e) { try { var path = DiagnosticsBundle.Export(); var open = MessageBox.Show( this, $"Diagnostic bundle written to:\n\n{path}\n\nOpen the containing folder?", "TeamsISO — Diagnostics exported", MessageBoxButton.YesNo, MessageBoxImage.Information); if (open == MessageBoxResult.Yes) { try { Process.Start(new ProcessStartInfo { FileName = "explorer.exe", Arguments = $"/select,\"{path}\"", UseShellExecute = true, }); } catch { /* shell launch failure is best-effort */ } } } catch (Exception ex) { MessageBox.Show( this, $"Diagnostic export failed.\n\n{ex.Message}", "TeamsISO — Diagnostic export", MessageBoxButton.OK, MessageBoxImage.Warning); } } /// /// Click handler for "Check for updates". Disables the button while the /// HTTP call is in flight (so a second click doesn't spawn parallel /// requests), then surfaces the result via MessageBox. On /// we offer /// to open the releases page so the operator can grab the new MSI. /// private async void OnCheckUpdate(object sender, RoutedEventArgs e) { UpdateButton.IsEnabled = false; try { var result = await UpdateChecker.CheckAsync(); switch (result.Status) { case UpdateChecker.UpdateStatus.UpdateAvailable: var open = MessageBox.Show( this, $"{result.Message}\n\n" + $"You're on {result.CurrentVersion}; latest is {result.LatestTag}.\n\n" + "Open the releases page to download the new MSI?", "TeamsISO — Update available", MessageBoxButton.YesNo, MessageBoxImage.Information); if (open == MessageBoxResult.Yes) UpdateChecker.OpenReleasesPage(); break; case UpdateChecker.UpdateStatus.UpToDate: MessageBox.Show( this, result.Message ?? "You're on the latest release.", "TeamsISO — Up to date", MessageBoxButton.OK, MessageBoxImage.Information); break; case UpdateChecker.UpdateStatus.Error: default: MessageBox.Show( this, $"Couldn't check for updates.\n\n{result.Message}", "TeamsISO — Update check failed", MessageBoxButton.OK, MessageBoxImage.Warning); break; } } finally { UpdateButton.IsEnabled = true; } } /// /// Open the company site in the default browser. We intentionally use the /// shell's URL handler rather than a tab inside the app — this is a /// "tell me more" link, not a workflow. /// private void OnWebsiteClick(object sender, RoutedEventArgs e) { try { Process.Start(new ProcessStartInfo { FileName = "https://wilddragon.net", UseShellExecute = true, }); } catch { // best-effort; if shell launch fails the click is a no-op } } }