214 lines
7.4 KiB
C#
214 lines
7.4 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Modal "About" dialog. Surfaces enough info that a user filing a support ticket
|
|
/// can paste version + NDI runtime + OS in a single screenshot.
|
|
/// </summary>
|
|
public partial class AboutWindow : Window
|
|
{
|
|
public AboutWindow()
|
|
{
|
|
InitializeComponent();
|
|
PopulateText();
|
|
}
|
|
|
|
private void PopulateText()
|
|
{
|
|
var asm = typeof(App).Assembly;
|
|
var info = asm.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.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<NdiInteropPInvoke>.Instance);
|
|
return interop.GetRuntimeVersion();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return $"not initialized ({ex.Message})";
|
|
}
|
|
}
|
|
|
|
private void OnClose(object sender, RoutedEventArgs e) => Close();
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
private void OnShowOnboarding(object sender, RoutedEventArgs e)
|
|
{
|
|
var onboarding = new OnboardingWindow { Owner = this };
|
|
onboarding.ShowDialog();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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"));
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// <see cref="UpdateChecker.UpdateStatus.UpdateAvailable"/> we offer
|
|
/// to open the releases page so the operator can grab the new MSI.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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
|
|
}
|
|
}
|
|
}
|