Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ That paragraph is not decoration: the release workflow copies each entry verbati
the GitHub release body and the announcement discussion, so it is the first thing a
prospective user reads. CI fails a pull request whose newest entry is missing it.

## [1.76.15] - 2026-09-04

On any of the six light colour themes, the green tick on the little "finished" pop-up was almost invisible
against its own background. It was a fixed green picked for the dark themes and never changed for the others.

### Fixed
- **The "finished" pop-up's tick is readable on the light themes.** Its background follows whichever theme you
picked, but the tick, its circle and the border were fixed to one green chosen against a dark background. On
the light themes that left the tick at between 1.65 and 2.08 times the contrast of its background, where 4.5
is the readable threshold — so the pop-up said something had finished and you could barely see the mark
confirming it. All three now come from the theme, which already keeps a lighter green for dark themes and a
darker one for light. A check now fails the build if any screen fixes a colour the theme cannot change.

## [1.76.14] - 2026-09-04

Double-clicking a cell in the App Updates or Windows Update list used to put a cursor in it, as if you could
Expand Down
74 changes: 74 additions & 0 deletions SysManager/SysManager.Tests/ArchitectureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5496,6 +5496,80 @@ public void TheTimerResolutionQuery_BindsItsOutParametersCoarsestFinestCurrent()
private static partial Regex TimerQueryCall();


/// <summary>
/// A view may not paint itself with a literal colour; the theme decides colours.
/// </summary>
/// <remarks>
/// The completion toast fixed three greens at <c>#22C55E</c> — the DARK-mode value — while its container
/// followed the theme through <c>Surface2</c>. Measured against each preset's real <c>Surface2</c>, the
/// tick came out at 1.65:1 on soft-blossom and never better than 2.08:1 on any of the six light presets,
/// against 7.66:1 on midnight-indigo where the value was chosen. WCAG asks 4.5:1 for text and 3:1 for a
/// meaningful graphic; it cleared neither.
/// <para><c>NoThemedFill_CarriesAHardcodedWhiteForeground</c> pins the same class and could not see this
/// one: it reads App.xaml styles whose Background binds <c>Accent</c> or <c>Danger</c>, and looks for the
/// literal <c>White</c>. Different file, different fill, different literal. This is the general rule, and
/// it is cheap because the view layer is nearly clean already — seven literals in total before the toast
/// was fixed, four of which are legitimate.</para>
/// </remarks>
[Fact]
public void NoViewPaintsItselfWithALiteralColour()
{
// file -> the reason its literals are colours being SHOWN rather than colours being applied.
var swatches = new Dictionary<string, string>(StringComparer.Ordinal)
{
["ThemePopup.xaml"] = "the custom-theme editor's 24x24 preview squares: each is an x:Name'd Border "
+ "whose fill the code-behind replaces with the value being edited, so the "
+ "literal is a designer-time default and the swatch's job is to BE a colour",
};

// Literals that must NOT follow the theme, allowed by exact value and only where they appear. The
// FocusRing is two stacked strokes precisely because no single themed colour survives every surface
// it lands on — PrimaryButton's accent fill, DangerButton's red, a raised grey and a card — where the
// accent itself falls to 1.00:1 against one of them. Theme-independence is the feature.
var themeIndependent = new Dictionary<string, string[]>(StringComparer.Ordinal)
{
["App.xaml"] = ["Stroke=\"#111111\"", "Stroke=\"#FFFFFF\""],
};

var appDir = FindAppProjectDir();
var files = Directory.GetFiles(appDir, "*.xaml")
.Concat(Directory.GetFiles(Path.Combine(appDir, "Views"), "*.xaml"))
.Where(f => !f.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}",
StringComparison.Ordinal))
.ToList();

// Vacuity floor: the view layer is 30-odd files. Zero would mean the enumeration broke.
Assert.True(files.Count >= 25,
$"only {files.Count} view files were enumerated — this guard is reading the wrong folder.");

var offenders = new List<string>();
foreach (var file in files)
{
var name = Path.GetFileName(file);
if (swatches.ContainsKey(name)) continue;

var text = File.ReadAllText(file);
var allowed = themeIndependent.TryGetValue(name, out var values) ? values : [];
foreach (var m in LiteralColourAttribute().Matches(text).Cast<Match>())
{
if (allowed.Contains(m.Value, StringComparer.Ordinal)) continue;
var line = text[..m.Index].Count(c => c == '\n') + 1;
offenders.Add($"{name}:{line} {m.Value}");
}
}

Assert.True(offenders.Count == 0,
"these views set a colour the theme cannot change, so whichever preset they were eyeballed against "
+ "is the only one they are correct on. Bind a themed brush — Success/SuccessText/SuccessBorder, "
+ "Danger…, TextPrimary, Surface… — or, if the element's purpose is to display a colour rather "
+ "than be styled by one, name the file in the exception list in this test WITH that reason:\n "
+ string.Join("\n ", offenders));
}

/// <summary>A colour-bearing attribute given a literal hex value.</summary>
[GeneratedRegex(@"(?:Foreground|Background|Fill|Stroke|BorderBrush)=""#[0-9A-Fa-f]{6,8}""")]
private static partial Regex LiteralColourAttribute();

/// <summary>
/// A text column in a report grid must not accept typing.
/// </summary>
Expand Down
12 changes: 9 additions & 3 deletions SysManager/SysManager/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,14 @@
HorizontalAlignment="Right" VerticalAlignment="Bottom"
AutomationProperties.LiveSetting="Assertive"
Margin="0,0,20,20" Visibility="Collapsed">
<!-- Themed status brushes, not literal greens. The container follows the theme via Surface2
while the three greens here were fixed at #22C55E — the DARK-mode value — so the tick
measured 1.65:1 on soft-blossom and never better than 2.08:1 on any light preset, against
7.66:1 on midnight-indigo where it was chosen. ThemeService already seeds Success per mode
(#22C55E dark, #166534 light) for exactly this reason; its own comment beside those values
calls the failure "one crisp card beside two washed-out ones". -->
<Border Background="{DynamicResource Surface2}" CornerRadius="10"
BorderBrush="#4022C55E" BorderThickness="1"
BorderBrush="{DynamicResource SuccessBorder}" BorderThickness="1"
Padding="14,12,18,12">
<Border.Effect>
<DropShadowEffect ShadowDepth="4" BlurRadius="24" Opacity="0.5" Color="Black"/>
Expand All @@ -511,9 +517,9 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Width="28" Height="28" CornerRadius="14"
Background="#2022C55E" Margin="0,0,10,0">
Background="{DynamicResource SuccessBgSubtle}" Margin="0,0,10,0">
<TextBlock Text="&#xE73E;" FontFamily="Segoe Fluent Icons,Segoe MDL2 Assets"
FontSize="14" Foreground="#22C55E"
FontSize="14" Foreground="{DynamicResource Success}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
Expand Down
6 changes: 3 additions & 3 deletions SysManager/SysManager/SysManager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<RootNamespace>SysManager</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>NU1603;NU1701</NoWarn>
<Version>1.76.14</Version>
<FileVersion>1.76.14.0</FileVersion>
<AssemblyVersion>1.76.14.0</AssemblyVersion>
<Version>1.76.15</Version>
<FileVersion>1.76.15.0</FileVersion>
<AssemblyVersion>1.76.15.0</AssemblyVersion>
<Product>SysManager</Product>
<Description>SysManager — Windows system monitoring toolkit by laurentiu021. Network, updates, health, logs, safe deep cleanup.</Description>
<PackageProjectUrl>https://github.com/laurentiu021/SystemManager</PackageProjectUrl>
Expand Down