Fixes every finding the new quality gate reports, without changing behavior: - One type per file (MA0048): AppBrand, Attribution, NullActivityLog, LogSnapshot, ISanitizable, AppTheme, UpdateCheckResult, UpdateText, IUpdateBackend, ContentDialogPrompter, WindowExtensions, MessageBoxPrompter, and the samples' SampleSettings/SampleSettingsContext get their own files (the samples now link samples/Shared/*.cs). - Regex match timeouts on the two generated regexes (MA0009). - AppInfo.Id reports nameof(value) as the parameter (MA0015); test updated. - Splash dismissal is a named DismissAfterAsync started through the dispatcher (MA0147, MA0134), and the WinUI splash constructor is split into builders (MA0051). The WPF countdown must go through the dispatcher: the sample builds its window before Application.Run, when no synchronization context exists. - The WinUI sample's startup update check is a named method (MA0147). - CA1859 in BrandTool and the version tests; private static readonly fields renamed to s_camelCase (IDE1006). - A header comment on every type and method (K22-CODE-09/CS-04): hand-written for library, sample, and tool code; test methods summarize their Subject_Behavior names. Verified: zero-warning x64 build, 115 unit tests with 100% line coverage of KofTwentyTwo.AppKit and KofTwentyTwo.AppKit.Updates, 12 UI tests, and dotnet format --verify-no-changes --severity warn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: James Maes <james@kof22.com>
147 lines
4.7 KiB
C#
147 lines
4.7 KiB
C#
/*
|
|
* Copyright (c) 2026 James Maes (KofTwentyTwo)
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
using KofTwentyTwo.AppKit.Settings;
|
|
using KofTwentyTwo.AppKit.Updates;
|
|
using KofTwentyTwo.AppKit.WinUI;
|
|
using Microsoft.UI.Xaml;
|
|
|
|
|
|
namespace AppKit.Sample.WinUI;
|
|
|
|
/// <summary>The sample's main window: each control exercises one AppKit service.</summary>
|
|
public sealed partial class MainWindow : Window
|
|
{
|
|
private readonly SampleSettings _settings = SampleApp.SettingsStore.Load();
|
|
private readonly UpdateCoordinator _updates;
|
|
|
|
|
|
|
|
/// <summary>Sizes and brands the window, wires the update coordinator, restores the saved settings, shows the splash, and schedules the quiet startup update check.</summary>
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
Title = SampleApp.Info.DisplayName;
|
|
this.ResizeForDpi(900, 600);
|
|
this.SetMinimumSize(640, 420);
|
|
this.SetAppIcon(SampleApp.Info);
|
|
|
|
_updates = new UpdateCoordinator(
|
|
new VelopackUpdateService(SampleApp.Info.RepositoryUrl!),
|
|
new ContentDialogPrompter(() => Content.XamlRoot),
|
|
SampleApp.Info.DisplayName,
|
|
App.Log);
|
|
|
|
GreetingText.Text = _settings.Greeting;
|
|
SplashToggle.IsChecked = _settings.ShowSplashScreen;
|
|
(_settings.ThemeKind switch { AppTheme.Light => ThemeLight, AppTheme.Dark => ThemeDark, _ => ThemeSystem }).IsChecked = true;
|
|
|
|
SplashOverlay.ShowOver(RootGrid, SampleApp.Info, _settings);
|
|
Closed += (_, _) => LogWindow.CloseCurrent(); // a log-only process would linger otherwise
|
|
|
|
if(_settings.CheckForUpdatesOnStartup)
|
|
{
|
|
// The constructor runs on the UI thread, so the check resumes there to show dialogs.
|
|
_ = CheckForUpdatesAfterStartupAsync();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Waits for the splash to clear (dialogs need the window's XamlRoot), then runs the
|
|
/// quiet startup update check, which only speaks up when an update exists.
|
|
/// </summary>
|
|
private async Task CheckForUpdatesAfterStartupAsync()
|
|
{
|
|
await Task.Delay(_settings.ShowSplashScreen ? _settings.SplashMilliseconds + 500 : 1000);
|
|
await _updates.CheckQuietlyAsync();
|
|
}
|
|
|
|
|
|
|
|
/// <summary>File, Exit.</summary>
|
|
private void Exit_Click(object sender, RoutedEventArgs e) => Close();
|
|
|
|
|
|
|
|
/// <summary>View, theme: applies the chosen theme to the window and saves it.</summary>
|
|
private void Theme_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_settings.Theme = (string)((FrameworkElement)sender).Tag;
|
|
WinUIShell.ApplyTheme(RootGrid, _settings.ThemeKind);
|
|
Save();
|
|
}
|
|
|
|
|
|
|
|
/// <summary>View, Show splash at startup: saves the preference.</summary>
|
|
private void Splash_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_settings.ShowSplashScreen = SplashToggle.IsChecked;
|
|
Save();
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Help, Check for updates: runs the interactive update flow.</summary>
|
|
private async void CheckForUpdates_Click(object sender, RoutedEventArgs e) => await _updates.CheckInteractivelyAsync();
|
|
|
|
|
|
|
|
/// <summary>Help, Activity log: opens the live log window, or brings the open one forward.</summary>
|
|
private void ActivityLog_Click(object sender, RoutedEventArgs e) => LogWindow.ShowSingle(App.Log, SampleApp.Info);
|
|
|
|
|
|
|
|
/// <summary>Help, About: shows the About dialog.</summary>
|
|
private async void About_Click(object sender, RoutedEventArgs e) => await AboutDialog.ShowAsync(SampleApp.Info, Content.XamlRoot);
|
|
|
|
|
|
|
|
/// <summary>Writes an INFO entry, to show logging.</summary>
|
|
private void LogInfo_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
App.Log.Info("The user pressed 'Write a log entry'.");
|
|
StatusText.Text = "Wrote an INFO entry.";
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Logs a handled exception with its stack trace, to show error logging.</summary>
|
|
private void LogError_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
throw new InvalidOperationException("A deliberately handled sample failure.");
|
|
}
|
|
catch(InvalidOperationException ex)
|
|
{
|
|
App.Log.Error("Sample operation failed.", ex);
|
|
StatusText.Text = "Wrote an ERROR entry with its stack trace.";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Throws on purpose, to show that the crash net logs the exception and the app keeps running.</summary>
|
|
private void Throw_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
StatusText.Text = "Threw; the crash net logged it and the app kept running.";
|
|
throw new InvalidOperationException("Deliberately unhandled sample exception.");
|
|
}
|
|
|
|
|
|
|
|
/// <summary>Saves the settings and reports a failed save in the status line.</summary>
|
|
private void Save()
|
|
{
|
|
if(!SampleApp.SettingsStore.Save(_settings))
|
|
{
|
|
StatusText.Text = "Could not save settings.";
|
|
}
|
|
}
|
|
}
|