From f0299e2407cce6e3133e05d8eb822866de053cbb Mon Sep 17 00:00:00 2001 From: GabrielDuf Date: Wed, 3 Jun 2026 13:58:51 -0400 Subject: [PATCH 1/4] Don't flash the "no updates found" message during reload --- .../ViewModels/SoftwarePages/PackagesPageViewModel.cs | 5 +++-- .../AbstractPackageLoader.cs | 7 ++++++- .../Pages/SoftwarePages/AbstractPackagesPage.xaml.cs | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs index 310e46ea43..9c2fad2575 100644 --- a/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs +++ b/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs @@ -518,8 +518,10 @@ public void FilterPackages(bool fromQuery = false) if (FilteredPackages.Count == 0) { + // Don't show the "no packages" message while a reload is in progress; the list is + // momentarily empty and the message would flash misleadingly. BackgroundText = string.IsNullOrWhiteSpace(query) ? NoPackagesText : NoMatchesText; - BackgroundTextVisible = !MegaQueryBoxEnabled || !string.IsNullOrWhiteSpace(query); + BackgroundTextVisible = !Loader.IsLoading && (!MegaQueryBoxEnabled || !string.IsNullOrWhiteSpace(query)); } else { @@ -533,7 +535,6 @@ public async Task LoadPackages(ReloadReason reason = ReloadReason.External) if (!Loader.IsLoading && (!Loader.IsLoaded || reason is ReloadReason.External or ReloadReason.Manual or ReloadReason.Automated)) { - Loader.ClearPackages(emitFinishSignal: false); await Loader.ReloadPackages(); } } diff --git a/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs b/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs index ad85de9a73..be5139222b 100644 --- a/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs +++ b/src/UniGetUI.PackageEngine.PackageLoader/AbstractPackageLoader.cs @@ -144,12 +144,17 @@ public virtual async Task ReloadPackages() return; } - ClearPackages(emitFinishSignal: false); LoadOperationIdentifier = new Random().Next(); int current_identifier = LoadOperationIdentifier; IsLoading = true; StartedLoading?.Invoke(this, EventArgs.Empty); + // Clear packages only after signaling the load started, so the UI shows the + // loading state instead of briefly flashing the "no packages found" message. + PackageReference.Clear(); + IsLoaded = false; + InvokePackagesChangedEvent(false, [], []); + if (REQUIRES_INTERNET) { await CoreTools.WaitForInternetConnection(); diff --git a/src/UniGetUI/Pages/SoftwarePages/AbstractPackagesPage.xaml.cs b/src/UniGetUI/Pages/SoftwarePages/AbstractPackagesPage.xaml.cs index df6e550490..a4443af0af 100644 --- a/src/UniGetUI/Pages/SoftwarePages/AbstractPackagesPage.xaml.cs +++ b/src/UniGetUI/Pages/SoftwarePages/AbstractPackagesPage.xaml.cs @@ -697,7 +697,6 @@ protected async Task LoadPackages(ReloadReason reason) ) ) { - Loader.ClearPackages(emitFinishSignal: false); await Loader.ReloadPackages(); } } From 8407c8dcfc756a76f685855f0f40b6dc74db4390 Mon Sep 17 00:00:00 2001 From: GabrielDuf Date: Wed, 3 Jun 2026 15:11:50 -0400 Subject: [PATCH 2/4] Fix transparent tray context menu under Mica --- .../Assets/Styles/Styles.WindowsMica.axaml | 6 ++-- .../Infrastructure/MicaWindowHelper.cs | 28 ++++++++++++++----- src/UniGetUI.Avalonia/Views/MainWindow.axaml | 2 ++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml b/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml index 6d44525f10..bce364e4f6 100644 --- a/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml +++ b/src/UniGetUI.Avalonia/Assets/Styles/Styles.WindowsMica.axaml @@ -25,7 +25,7 @@ - + @@ -61,8 +61,8 @@ - + diff --git a/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs b/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs index 0f85fd8ebe..c7f6dbda43 100644 --- a/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs +++ b/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs @@ -21,7 +21,8 @@ internal static class MicaWindowHelper private const int DWMWA_BORDER_COLOR = 34; private const int DWMWA_SYSTEMBACKDROP_TYPE = 38; private const int DWMWCP_ROUND = 2; - private const int DWMSBT_MAINWINDOW = 2; // Mica — same backdrop as the rest of the app, so menus match + private const int DWMSBT_MAINWINDOW = 2; // Mica — for long-lived windows (dialogs) + private const int DWMSBT_TRANSIENTWINDOW = 3; // Acrylic — for transient surfaces (menus/flyouts); Mica won't paint on these private const int DWMWA_COLOR_DEFAULT = unchecked((int)0xFFFFFFFF); private static bool _acrylicPopupsHooked; @@ -69,15 +70,28 @@ public static void EnableAcrylicPopups() return; _acrylicPopupsHooked = true; - // Every flyout/menu/tooltip/combo popup is hosted in a PopupRoot; style it as it loads. + // In-app flyouts/menus/tooltips/combo popups are hosted in a PopupRoot; style each as it loads. Control.LoadedEvent.AddClassHandler((root, _) => ApplyAcrylicToPopup(root)); + + // The system-tray context menu is NOT a PopupRoot — Avalonia hosts it in its own Window + // (Avalonia.Win32.TrayIconImpl.TrayPopupRoot), so it misses the handler above and would + // render with no backdrop (transparent over the desktop). Catch it by type name and apply + // the same acrylic treatment. The other Windows (MainWindow/dialogs) are handled via Apply(). + Control.LoadedEvent.AddClassHandler((win, _) => + { + if (win.GetType().Name == "TrayPopupRoot") + ApplyAcrylicToPopup(win); + }); } - private static void ApplyAcrylicToPopup(PopupRoot root) + private static void ApplyAcrylicToPopup(TopLevel root) { - // Transparent surface so the DWM acrylic shows; the presenter backgrounds are also - // transparent (Styles.WindowsMica) so only the acrylic + menu items are painted. - root.TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent }; + // Request acrylic (not Transparent): the Transparent level makes a layered window, and DWM + // system backdrops never paint on those — so the popup ended up fully see-through with only + // the presenter tint, unreadable when shown over the desktop (e.g. the tray menu). AcrylicBlur + // gives a composited window DWM can actually fill. This path only runs when Mica is enabled + // (Win11 + transparency effects), so acrylic is always available here. + root.TransparencyLevelHint = new[] { WindowTransparencyLevel.AcrylicBlur, WindowTransparencyLevel.Blur }; root.Background = Brushes.Transparent; if (root.TryGetPlatformHandle()?.Handle is not { } handle || handle == 0) @@ -85,7 +99,7 @@ private static void ApplyAcrylicToPopup(PopupRoot root) int corner = DWMWCP_ROUND; NativeMethods.DwmSetWindowAttribute(handle, DWMWA_WINDOW_CORNER_PREFERENCE, ref corner, sizeof(int)); - int backdrop = DWMSBT_MAINWINDOW; + int backdrop = DWMSBT_TRANSIENTWINDOW; NativeMethods.DwmSetWindowAttribute(handle, DWMWA_SYSTEMBACKDROP_TYPE, ref backdrop, sizeof(int)); } diff --git a/src/UniGetUI.Avalonia/Views/MainWindow.axaml b/src/UniGetUI.Avalonia/Views/MainWindow.axaml index fa60f3d359..32f70d8a04 100644 --- a/src/UniGetUI.Avalonia/Views/MainWindow.axaml +++ b/src/UniGetUI.Avalonia/Views/MainWindow.axaml @@ -362,6 +362,8 @@ FontSize="15" CornerRadius="0" BorderThickness="0" + VerticalContentAlignment="Center" + Padding="8,0,4,0" Background="Transparent" PlaceholderText="{Binding GlobalSearchPlaceholder}" IsEnabled="{Binding GlobalSearchEnabled}" From bf622d3a7851e9d4fa201b5f339c23ea2cfd765f Mon Sep 17 00:00:00 2001 From: GabrielDuf Date: Wed, 3 Jun 2026 15:29:08 -0400 Subject: [PATCH 3/4] Remove unused DWMSBT_MAINWINDOW constant --- src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs b/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs index c7f6dbda43..7987e2a697 100644 --- a/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs +++ b/src/UniGetUI.Avalonia/Infrastructure/MicaWindowHelper.cs @@ -21,7 +21,6 @@ internal static class MicaWindowHelper private const int DWMWA_BORDER_COLOR = 34; private const int DWMWA_SYSTEMBACKDROP_TYPE = 38; private const int DWMWCP_ROUND = 2; - private const int DWMSBT_MAINWINDOW = 2; // Mica — for long-lived windows (dialogs) private const int DWMSBT_TRANSIENTWINDOW = 3; // Acrylic — for transient surfaces (menus/flyouts); Mica won't paint on these private const int DWMWA_COLOR_DEFAULT = unchecked((int)0xFFFFFFFF); From e8f597b55169ca317ef0c2ea29f1e2a194ecc99d Mon Sep 17 00:00:00 2001 From: GabrielDuf Date: Wed, 3 Jun 2026 15:47:25 -0400 Subject: [PATCH 4/4] Show "Loading packages" instead of "no updates" while loading --- .../SoftwarePages/PackagesPageViewModel.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs b/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs index 9c2fad2575..c5b106bdea 100644 --- a/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs +++ b/src/UniGetUI.Avalonia/ViewModels/SoftwarePages/PackagesPageViewModel.cs @@ -126,6 +126,7 @@ partial void OnIsFilterPaneOpenChanged(bool value) public readonly bool MegaQueryBoxEnabled; public readonly bool DisableFilterOnQueryChange; public readonly bool DisableReload; + public readonly bool LoadsOnStart; public readonly bool RoleIsUpdateLike; public bool SimilarSearchEnabled { get; private set; } public readonly string NoPackagesText; @@ -206,6 +207,7 @@ public PackagesPageViewModel(PackagesPageData data) DisableFilterOnQueryChange = data.DisableFilterOnQueryChange; MegaQueryBoxEnabled = data.MegaQueryBlockEnabled; DisableReload = data.DisableReload; + LoadsOnStart = !data.DisableAutomaticPackageLoadOnStart; _showLastCheckedTime = data.ShowLastLoadTime; NoPackagesText = data.NoPackages_BackgroundText; NoMatchesText = data.NoMatches_BackgroundText; @@ -516,12 +518,17 @@ public void FilterPackages(bool fromQuery = false) UpdateSubtitle(); PackageCountUpdated?.Invoke(); - if (FilteredPackages.Count == 0) + bool loadingOrPending = Loader.IsLoading || (LoadsOnStart && !Loader.IsLoaded); + + if (loadingOrPending && FilteredPackages.Count == 0) + { + BackgroundText = _stillLoadingSubtitle; + BackgroundTextVisible = true; + } + else if (FilteredPackages.Count == 0) { - // Don't show the "no packages" message while a reload is in progress; the list is - // momentarily empty and the message would flash misleadingly. BackgroundText = string.IsNullOrWhiteSpace(query) ? NoPackagesText : NoMatchesText; - BackgroundTextVisible = !Loader.IsLoading && (!MegaQueryBoxEnabled || !string.IsNullOrWhiteSpace(query)); + BackgroundTextVisible = !MegaQueryBoxEnabled || !string.IsNullOrWhiteSpace(query); } else { @@ -828,7 +835,7 @@ public void UpdatePackageCount() // ─── Subtitle ───────────────────────────────────────────────────────────── public void UpdateSubtitle() { - if (Loader.IsLoading) + if (Loader.IsLoading || (LoadsOnStart && !Loader.IsLoaded)) { Subtitle = _stillLoadingSubtitle; return;