From 78dd93cfc252ffbecda0e8a34952468e98e83dae Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Wed, 1 Jul 2026 19:28:09 +0100 Subject: [PATCH] Fix WinWorldPC suggestion ranking to prioritize exact matches Platform/genre/company suggestion lists in AdminWwpcImportReviewViewModel sorted alphabetically after substring filtering, which could push an exact match (e.g. "Windows") off the visible list when many other entries shared the same prefix. Now exact matches rank first, followed by Jaro-Winkler similarity, then alphabetical order. --- .../Admin/AdminWwpcImportReviewViewModel.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Marechai.App/Presentation/ViewModels/Admin/AdminWwpcImportReviewViewModel.cs b/Marechai.App/Presentation/ViewModels/Admin/AdminWwpcImportReviewViewModel.cs index f1e60e63..bc93c2db 100644 --- a/Marechai.App/Presentation/ViewModels/Admin/AdminWwpcImportReviewViewModel.cs +++ b/Marechai.App/Presentation/ViewModels/Admin/AdminWwpcImportReviewViewModel.cs @@ -12,6 +12,7 @@ using Marechai.App.Presentation.Views.Admin; using Marechai.App.Services; using Marechai.App.Services.Authentication; using Marechai.Data; +using Marechai.Data.Helpers; namespace Marechai.App.Presentation.ViewModels.Admin; @@ -174,16 +175,25 @@ public partial class AdminWwpcImportReviewViewModel : ObservableObject, IRegionA return "https://winworldpc.com" + (url.StartsWith('/') ? url : "/" + url); } + static IEnumerable RankByQuery(IEnumerable source, string query, Func nameSelector) + { + if(string.IsNullOrWhiteSpace(query)) + return source.OrderBy(nameSelector); + + return source.Where(i => (nameSelector(i) ?? string.Empty).Contains(query, StringComparison.OrdinalIgnoreCase)) + .OrderByDescending(i => string.Equals(nameSelector(i), query, StringComparison.OrdinalIgnoreCase)) + .ThenByDescending(i => JaroWinkler.Similarity(query, nameSelector(i) ?? string.Empty)) + .ThenBy(nameSelector); + } + public void UpdateGenreSuggestions(string query) { GenreSuggestions.Clear(); IEnumerable source = _allGenres.Where(g => g.Type == (int)SoftwareGenreType.Category && !SelectedGenres.Any(selected => selected.Id == g.Id)); - if(!string.IsNullOrWhiteSpace(query)) - source = source.Where(g => (g.Name ?? string.Empty).Contains(query, StringComparison.OrdinalIgnoreCase)); - foreach(SoftwareGenreDto genre in source.OrderBy(g => g.Name).Take(30)) + foreach(SoftwareGenreDto genre in RankByQuery(source, query, g => g.Name ?? string.Empty).Take(30)) GenreSuggestions.Add(genre); } @@ -191,11 +201,7 @@ public partial class AdminWwpcImportReviewViewModel : ObservableObject, IRegionA { CompanySuggestions.Clear(); - IEnumerable source = _allCompanies; - if(!string.IsNullOrWhiteSpace(query)) - source = source.Where(c => (c.Name ?? string.Empty).Contains(query, StringComparison.OrdinalIgnoreCase)); - - foreach(CompanyDto company in source.OrderBy(c => c.Name).Take(30)) + foreach(CompanyDto company in RankByQuery(_allCompanies, query, c => c.Name ?? string.Empty).Take(30)) CompanySuggestions.Add(company); } @@ -203,11 +209,7 @@ public partial class AdminWwpcImportReviewViewModel : ObservableObject, IRegionA { PlatformSuggestions.Clear(); - IEnumerable source = _allPlatforms; - if(!string.IsNullOrWhiteSpace(query)) - source = source.Where(p => (p.Name ?? string.Empty).Contains(query, StringComparison.OrdinalIgnoreCase)); - - foreach(SoftwarePlatformDto platform in source.OrderBy(p => p.Name).Take(30)) + foreach(SoftwarePlatformDto platform in RankByQuery(_allPlatforms, query, p => p.Name ?? string.Empty).Take(30)) PlatformSuggestions.Add(platform); }