Skip to content

Center the update count text inside the sidebar badge - #5574

Merged
Gabriel Dufresne (GabrielDuf) merged 1 commit into
mainfrom
fix/nav-update-badge-text-off-center
Oct 22, 2026
Merged

Gabriel Dufresne (GabrielDuf) merged 1 commit into
mainfrom
fix/nav-update-badge-text-off-center

Conversation

@GabrielDuf

Copy link
Copy Markdown
Contributor
  • I have read the contributing guidelines, and I agree with the Code of Conduct.
  • Have you checked that there aren't other open pull requests for the same changes?
  • Have you tested that the committed code can be executed without errors?
  • Have you confirmed that this issue is caused by UniGetUI itself, and not by the package manager or the package involved?

Bug report

There is no GitHub issue; the maintainer reported this directly. The number on the available-updates badge in the navigation bar is not quite centered. It sits a pixel or two too far to the left.

Root cause

The badge TextBlock in SidebarView.axaml (inside the update-count Border) used HorizontalAlignment="Center" with the default TextAlignment=Left. That centers the TextBlock's layout box in the Border's 10 DIP content area, not the text itself. Layout rounding rounds the box's desired width up to the device-pixel grid. At 9px bold Segoe UI a digit is just over 5 DIP wide, so the box becomes 6 DIP at 100%. The box is centered, but the glyph is drawn left-aligned inside it, so all the rounding slack ends up on the right.

In a headless Skia render with Segoe UI, the left/right ink gaps for a single digit were 5.0/6.0 DIP at 100%, 4.8/6.4 at 125% and 5.0/6.0 at 200%. That is about 1 DIP left of center at 100-125% and one physical pixel at 200%, which matches the report. The global TextTrimming=CharacterEllipsis style plays no part: the measurements were the same without it.

Fix

HorizontalAlignment="Center" is replaced with TextAlignment="Center" on the badge TextBlock. The TextBlock now uses its default Stretch alignment and fills the Border's content width. The text formatter centers the line on its real, unrounded advance width, so the slack is split evenly on both sides.

Stretch only affects arrange, not measure, so the Border still sizes to its content. The widths are unchanged: 16 DIP for one digit, 17 for two, 23 for "99+". The MinWidth circle and the negative-right-margin clipping fix are not affected. After the change, single-digit left/right ink gaps are within about 0.3 DIP at every scale from 100% to 200% (for example 5.5/5.5 at 200%, 5.6/5.6 at 125%). Two-digit counts and "99+" are within one rendered pixel.

Regression test

UniGetUI.Tests.SidebarUpdateBadgeTests.UpdateCountIsHorizontallyCenteredInItsBadge renders the real SidebarView headlessly with UpdatesBadgeCount set at a given render scaling. It finds the badge TextBlock and asserts that the gap from the Border's left edge to the start of the text line equals the gap from the end of the line to the Border's right edge, within 0.01. It covers counts 3, 42 and 150 ("99+") at scalings 1, 1.25, 1.5 and 2.

Verification

  • dotnet build UniGetUI.Avalonia.csproj -p:Platform=x64 -p:UseSharedCompilation=false: exit 0, 0 errors. The 18 warnings are pre-existing ones in files this change does not touch.
  • Filtered test run (FullyQualifiedName~SidebarUpdateBadgeTests): 7 of 7 pass with the fix. With SidebarView.axaml reverted, 2 of 7 fail (count 3 at scaling 1: left gap 4, right gap 3; count 3 at scaling 1.25: left 3.2, right 3.8).
  • dotnet format whitespace and dotnet format style with --verify-no-changes, on the new test file: both exit 0. The .axaml change is not processed by the C# formatters.
  • The full suite was not run locally; CI runs it.
  • Not verified visually in the running app. The numbers come from a headless Skia render with Segoe UI, not a screenshot of the real window.

Review notes (non-blocking)

  • The repo-wide dotnet format style src/UniGetUI.Windows.slnx --verify-no-changes exits 2 on IDE0060 at src/UniGetUI.PackageEngine.Tests/CargoManagedOperationRoutingTests.cs:155. That warning comes from main (Replace Cargo helper tools with native C# package management #5569), not this diff, but the CI style check may fail on this PR because of it.
  • The regression test runs on the headless stub font, not Segoe UI. Without the fix, the stub font leans the opposite way from the report (left 4, right 3). The test asserts the two gaps are equal, so it still catches the mechanism in both directions.
  • Please check the badge by eye at your DPI. "99+" may still look slightly left-heavy, because the '+' glyph's ink sits left within its advance width. That is font metrics and is out of scope here.
  • Other badges and pills (bundles badge, operation-panel indicators) may use the same HorizontalAlignment="Center" plus left-aligned text pattern. They were not audited.

🤖 Generated with Claude Code

The badge TextBlock was centered with HorizontalAlignment="Center" and
the default left TextAlignment. That centers the TextBlock's layout box,
whose desired width layout rounding pushes up to the device-pixel grid
(a 9px bold digit is just over 5 DIP, so the box becomes 6 DIP at 100%).
The glyph is then drawn left-aligned inside that box, so all of the
rounding slack lands on its right and the number sits about 1 DIP left
of center at 100-125% and one physical pixel left at 200%.

Using TextAlignment="Center" with the default Stretch alignment lets the
TextBlock fill the Border's content width and the text formatter center
the line on its real, unrounded advance width, splitting the slack
evenly. Stretch only affects arrange, so the Border still measures to
its content and keeps the same widths (16, 17 and 23 DIP for one digit,
two digits and "99+"), leaving the MinWidth circle and the
negative-right-margin clipping fix untouched.

SidebarUpdateBadgeTests renders the real SidebarView headlessly and
asserts the gap before and after the text line is equal for counts 3,
42 and "99+" at scalings 1, 1.25, 1.5 and 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused alignment change has targeted regression coverage and no identified blocking issues.

No open issues 🎉

What changed in this PR

Corrects horizontal centering of the available-updates count in UniGetUI’s sidebar badge without changing its sizing rules.

Changes:

  • Centers the text within the badge rather than centering the TextBlock’s layout box.
  • Adds seven headless regression cases covering single-digit, two-digit, and “99+” counts at multiple display scales.
File Description
src/​UniGetUI.Tests/​SidebarUpdateBadgeTests.cs Adds layout assertions that verify equal horizontal gaps around the update count.
src/​UniGetUI.Avalonia/​Views/​SidebarView.axaml Replaces horizontal control alignment with centered text alignment.

Review effort: Balanced

@randy-but-a-ro randy-but-a-ro Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Pull request was approved automatically: the AI review is complete and all its review threads are resolved. 🎉

Integration Details
{
	"deliveryId": "766b2f40-ce1f-11f1-83ce-5269b3d9f175",
	"headSha": "0a45d1a975b53bcc4188a373f2dd1c73612b76dc",
	"reviewer": "copilot-pull-request-reviewer[bot]"
}

@GabrielDuf
Gabriel Dufresne (GabrielDuf) merged commit c410dec into main Oct 22, 2026
6 checks passed
@GabrielDuf
Gabriel Dufresne (GabrielDuf) deleted the fix/nav-update-badge-text-off-center branch October 22, 2026 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants