Give the application a settings area built from what really exists

This commit is contained in:
2026-08-08 14:17:19 +02:00
parent 422d5ca10e
commit c8507b44fe
42 changed files with 3810 additions and 1083 deletions
@@ -106,10 +106,19 @@ internal sealed class KnownHostRowViewModel(
internal sealed partial class KnownHostsViewModel : ObservableObject
{
private readonly VaultViewModel vault;
private readonly Action? onBack;
internal KnownHostsViewModel(VaultViewModel vault)
/// <param name="vault">Where the pins, the reload and the withdrawal all actually live.</param>
/// <param name="onBack">
/// What the v5c header's own back arrow does — a delegate rather than a reference up to
/// <c>MainWindowViewModel</c>, on the same reasoning <c>ImportViewModel</c>'s own <c>onCancel</c> is one:
/// this type has no business knowing <c>ShellScreen</c> exists. Null in a layout test that builds this
/// directly makes the button a no-op rather than a crash.
/// </param>
internal KnownHostsViewModel(VaultViewModel vault, Action? onBack = null)
{
this.vault = vault;
this.onBack = onBack;
// The vault rebuilds this list on every reload and every sync pass, and a screen showing a stale
// copy of a trust decision is the one kind of staleness that matters here.
@@ -155,6 +164,14 @@ internal sealed partial class KnownHostsViewModel : ObservableObject
internal bool HasPins => Shown.Any();
/// <summary>
/// How many approved host keys this machine can see, before the filter box narrows the table — the v5c
/// header's own count chip. Unfiltered, on the same reasoning <see cref="Summary"/> reads off
/// <see cref="Shown"/> rather than <see cref="VisiblePins"/>: it is a fact about the list, not about
/// whatever somebody last typed into the filter.
/// </summary>
internal int Count => Shown.Count();
internal bool HasVisiblePins => VisiblePins.Count > 0;
internal bool HasSelection => Selected is not null;
@@ -218,6 +235,22 @@ internal sealed partial class KnownHostsViewModel : ObservableObject
await vault.ForgetPinCommand.ExecuteAsync(null).ConfigureAwait(true);
}
/// <summary>Puts the selected pin's fingerprint on the clipboard. Forwarded, like <see cref="ForgetSelectedAsync"/>.</summary>
[RelayCommand]
private async Task CopyFingerprintAsync()
{
if (Selected is null)
{
return;
}
await vault.CopyPinFingerprintCommand.ExecuteAsync(null).ConfigureAwait(true);
}
/// <summary>The header's own back arrow: to the Keychain screen this list was pulled out of.</summary>
[RelayCommand]
private void Back() => onBack?.Invoke();
internal void Detach() => vault.KnownHostPins.CollectionChanged -= OnPinsChanged;
partial void OnFilterChanged(string value) => Rebuild();
@@ -247,6 +280,7 @@ internal sealed partial class KnownHostsViewModel : ObservableObject
Selected = VisiblePins.FirstOrDefault(pin => pin.EntityId == selectedId);
OnPropertyChanged(nameof(HasPins));
OnPropertyChanged(nameof(Count));
OnPropertyChanged(nameof(HasVisiblePins));
OnPropertyChanged(nameof(Summary));
OnPropertyChanged(nameof(EmptyMessage));