Files
james.maesandClaude Opus 5.5 839fb72bec chore: adopt the KofTwentyTwo standards (#2)
## What

Brings AppKit into conformance with
[KofTwentyTwo/standards](https://github.com/KofTwentyTwo/standards).
Reviewable commit by commit:

| Commit | Change |
| --- | --- |
| build | Quality gate from `configs/dotnet` (analyzers incl. Meziantou,
warnings as errors), `packages.lock.json` per project, locked-mode
restore |
| style | Kingsrook layout and LF line endings, produced mechanically by
`dotnet format` (formatting only) |
| docs | SPDX license header on every C# file |
| refactor | Real code changes: analyzer findings fixed (one type per
file, regex timeouts, async void, …) and header comments on every type
and member |
| ci | Old workflows replaced by callers of the shared standards
workflows (PR gates, security, CodeQL, .NET CI, NuGet release with SBOM
+ attestation + trusted publishing), Scorecard |
| docs | README, CONTRIBUTING (GitHub Flow, DCO, signing), SECURITY,
CODEOWNERS, templates, Dependabot, threat model, ADRs, RELEASING |

Also includes `dev`'s CI fix, so it supersedes #1; the `dev` branch goes
away under GitHub Flow.

## Why

AppKit is the first Product repository to adopt the standards. Static
conformance before: 16 FAIL; after: 0 FAIL, 0 WARN (the remaining
UNKNOWN rows are GitHub settings and rulesets, applied separately).

## How tested

Locally with `CI=true` (lock files enforced): locked restore x64 and
ARM64; zero-warning x64 build; 115 unit tests with 100% line coverage of
`KofTwentyTwo.AppKit` and `KofTwentyTwo.AppKit.Updates`; 12 FlaUI UI
tests (WinUI + WPF samples); `dotnet format --verify-no-changes
--severity warn` clean; pack produces 4 packages + symbols; actionlint,
zizmor (pedantic), gitleaks clean.

The UI tests caught a regression introduced while fixing MA0147 (the WPF
splash stopped dismissing because no UI context existed yet); fixed by
starting the countdown through the dispatcher in both packages.

## Notes

- `ci.yml` and `release.yml` are pinned to KofTwentyTwo/standards#3's
head commit; they are repinned after that PR merges.
- This pull request's new check names become required checks once the
repository's rulesets are updated.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: James Maes <james@kof22.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:43:17 -05:00

148 lines
4.4 KiB
C#

/*
* Copyright (c) 2026 James Maes (KofTwentyTwo)
* SPDX-License-Identifier: MIT
*/
using System.Windows;
using System.Windows.Controls;
using KofTwentyTwo.AppKit.Updates;
using KofTwentyTwo.AppKit.Wpf;
namespace AppKit.Sample.Wpf;
/// <summary>The sample&apos;s main window: each control exercises one AppKit service.</summary>
public partial class MainWindow : Window
{
private readonly SampleSettings _settings = SampleApp.SettingsStore.Load();
private readonly UpdateCoordinator _updates;
/// <summary>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.SetAppIcon(SampleApp.Info);
_updates = new UpdateCoordinator(
new VelopackUpdateService(SampleApp.Info.RepositoryUrl!),
new MessageBoxPrompter(() => this),
SampleApp.Info.DisplayName,
Program.Log);
GreetingText.Text = _settings.Greeting;
SplashToggle.IsChecked = _settings.ShowSplashScreen;
CheckTheme();
SplashOverlay.ShowOver(RootGrid, SampleApp.Info, _settings);
Closed += (_, _) => LogWindow.CloseCurrent();
if(_settings.CheckForUpdatesOnStartup)
{
Loaded += async (_, _) =>
{
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 Fluent theme to the application and saves it.</summary>
private void Theme_Click(object sender, RoutedEventArgs e)
{
_settings.Theme = (string)((FrameworkElement)sender).Tag;
WpfShell.ApplyTheme(Application.Current, _settings.ThemeKind);
CheckTheme();
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(Program.Log, SampleApp.Info);
/// <summary>Help, About: shows the About window.</summary>
private void About_Click(object sender, RoutedEventArgs e) => AboutWindow.Show(SampleApp.Info, this);
/// <summary>Writes an INFO entry, to show logging.</summary>
private void LogInfo_Click(object sender, RoutedEventArgs e)
{
Program.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)
{
Program.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>Checks the View menu item that matches the saved theme and clears the others.</summary>
private void CheckTheme()
{
foreach(MenuItem item in new[] { ThemeSystem, ThemeLight, ThemeDark })
{
item.IsChecked = string.Equals((string)item.Tag, _settings.Theme, StringComparison.Ordinal);
}
}
/// <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.";
}
}
}