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
30 changes: 23 additions & 7 deletions src/UniGetUI.Avalonia/Models/PackageCollections.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Net.Http;
Expand Down Expand Up @@ -182,7 +183,7 @@
/// See issue #4617 — defense-in-depth signal that an upgrade may be redirecting the
/// download to a different domain than the user originally trusted.
/// </summary>
private void MaybeStartInstallerHostCheck()

Check warning on line 186 in src/UniGetUI.Avalonia/Models/PackageCollections.cs

View workflow job for this annotation

GitHub Actions / Linux (Avalonia)

Member 'MaybeStartInstallerHostCheck' does not access instance data and can be marked as static (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1822)

Check warning on line 186 in src/UniGetUI.Avalonia/Models/PackageCollections.cs

View workflow job for this annotation

GitHub Actions / Linux (Avalonia)

Member 'MaybeStartInstallerHostCheck' does not access instance data and can be marked as static (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1822)

Check warning on line 186 in src/UniGetUI.Avalonia/Models/PackageCollections.cs

View workflow job for this annotation

GitHub Actions / Linux (NativeAOT)

Member 'MaybeStartInstallerHostCheck' does not access instance data and can be marked as static (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1822)
{
#if WINDOWS
if (!Package.IsUpgradable) return;
Expand Down Expand Up @@ -489,19 +490,34 @@
public void SetSortDirection(bool ascending) => _ascending = ascending;

/// <summary>Returns <paramref name="items"/> in the current sort order.</summary>
public IEnumerable<PackageWrapper> ApplyToList(IEnumerable<PackageWrapper> items) =>
_ascending
? items.OrderBy(GetSortKey, StringComparer.OrdinalIgnoreCase)
: items.OrderByDescending(GetSortKey, StringComparer.OrdinalIgnoreCase);
public IEnumerable<PackageWrapper> ApplyToList(IEnumerable<PackageWrapper> items)
{
var comparer = Comparer<PackageWrapper>.Create((a, b) => Compare(a, b, CurrentSorter));
return _ascending ? items.OrderBy(w => w, comparer) : items.OrderByDescending(w => w, comparer);
}

// Shared by the "Order by" menu (ApplyToList) and the DataGrid's native column sorting
// (GetColumnComparer) so both order identically. Versions compare semantically via
// CoreTools.Version; a string key can't be used there because that struct has no ToString
// override, so its key would be a constant type name that never sorts.
private static int Compare(PackageWrapper a, PackageWrapper b, Sorter sorter) => sorter switch
{
Sorter.Version => a.Package.NormalizedVersion.CompareTo(b.Package.NormalizedVersion),
Sorter.NewVersion => a.Package.NormalizedNewVersion.CompareTo(b.Package.NormalizedNewVersion),
_ => string.Compare(GetSortKey(a, sorter), GetSortKey(b, sorter), StringComparison.OrdinalIgnoreCase),
};

private string GetSortKey(PackageWrapper w) => CurrentSorter switch
private static string GetSortKey(PackageWrapper w, Sorter sorter) => sorter switch
{
Sorter.Checked => w.IsChecked ? "0" : "1",
Sorter.Name => w.Package.Name,
Sorter.Id => w.Package.Id,
Sorter.Version => w.Package.NormalizedVersion.ToString() ?? string.Empty,
Sorter.NewVersion => w.Package.NormalizedNewVersion.ToString() ?? string.Empty,
Sorter.Source => w.Package.Source.AsString_DisplayName,
_ => w.Package.Name,
};

// Comparer for the DataGrid's native column sorting. Reflection-free (unlike SortMemberPath),
// so it keeps working under full-trim NativeAOT release builds — see issue #5103.
public static IComparer GetColumnComparer(Sorter sorter) =>
Comparer<PackageWrapper>.Create((a, b) => Compare(a, b, sorter));
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ or nameof(PackagesPageViewModel.SortAscending))
// Double-click a list row → show details
PackageList.DoubleTapped += (_, _) => _ = ShowDetailsForPackage(SelectedItem);

// Native DataGrid column sorting. The default SortMemberPath path resolves the property by
// reflection, which full-trim NativeAOT release builds strip away — so CanUserSort reports
// false and header clicks are silently dropped (issue #5103). A strongly-typed
// CustomSortComparer plus an explicit CanUserSort keeps Avalonia's built-in sort AOT-safe.
foreach (var col in PackageList.Columns)
{
ObservablePackageCollection.Sorter? sorter = (col.Tag as string) switch
{
"Name" => ObservablePackageCollection.Sorter.Name,
"Id" => ObservablePackageCollection.Sorter.Id,
"Version" => ObservablePackageCollection.Sorter.Version,
"NewVersion" => ObservablePackageCollection.Sorter.NewVersion,
"Source" => ObservablePackageCollection.Sorter.Source,
_ => null,
};
if (sorter is null) continue;
col.CanUserSort = true;
col.CustomSortComparer = ObservablePackageCollection.GetColumnComparer(sorter.Value);
}

// Keyboard shortcuts on the package list. Handled on the tunnel route (and even when
// already handled) because the DataGrid swallows Enter on the bubble route otherwise.
PackageList.AddHandler(KeyDownEvent, PackageList_KeyDown, RoutingStrategies.Tunnel, handledEventsToo: true);
Expand Down
Loading