Files
amacocian 794afa6c2c Blazor UI Migration (#1085)
* Migrate to Fluent UI

* Setup window events for Blazor WebView

* Setup basic FluentUI styling

* FluentUI links

* Setup views and viewmodel infra

* Remove old navigation logic

* Prepare an example of iframe embed

* Style window + navigation menu

* Setup page based navigation

* Add some UI error handling

* Introduce UI resiliency to exceptions

* Setup settings menu dropdown

* Basic setup for options views

* Setup reusable OptionBase

* Setup options views

* Basic styling

* Setup scoped css files.
Split App into components

* Hook option updates to OptionProvider

* Fix option dropdowns

* Setup multiple themes

* Make fonts scalable

* Move ViewModels under Views

* Launch view + styling

* Setup FocusView base

* Finish BuildListView implementation

* Base for build views

* Setup build routing

* Implement single build editor

* Implement skill description on hover

* Scrape skill information from the wiki and cache it locally

* Scrape and fix Guild Wars wiki info

* Improve mouse hover performance by querying position only when needed

* Skill snippet snaps to edges

* Setup accounts and executables view

* Launch configurations view

* Fix build skill icons
Attach skill types to skills
Scrape upkeep from wiki

* Fix skilltype overflow

* Adjust navigation menu

* Setup privilege elevation flow

* Setup MSAL

* Options synchronization view

* Telemetry view

* Version management and update view

* Setup plugins view

* Setup notifications panel

* Base for logs view

* Finish LogView

* Setup metrics view

* Setup UI logging interop

* GuildWarsPartySearch view implementation

* Setup gitlab mirror job

* Eventviewer base

* Remove gitlab mirror

* Remove mirror pipeline

* Fix metricsview crashes

* Extract progress component

* Setup trade chat views

* Setup Download view

* Extract progress styling

* Setup guild wars copy view

* Setup trade alerts

* Fix team template view skill selection

* Setup basic onboarding view

* Overhaul asynchronous progress operations and remove redundant versioning code

* Setup modsview base

* Setup modsview with mod states

* Setup mod installation process

* Cleanup more ui migration
Remove price history #1076

* Screen selector manage view

* Upgrade to .net 10
Closes #1078

* gMod management view

* Trader message notification

* ReShade management

* Update for toolbox

* Setup focusview fetching

* Setup CharacterComponent

* Setup vanquishing component

* Setup TitleInformationComponent

* Closes #1082
Fix API project for Guild Wars Reforged

* Small fixes + attempts to get new exe version

* FileId fixes

* Current Map and Player Resources widgets

* Quest log widget

* BuildComponent implementation

* Closes #1075
Embed wwwroot into the executable

* Cleanup

* Fixes to slnx

* Fix test project
2025-12-08 22:39:48 +01:00

86 lines
3.1 KiB
C#

using System.Extensions;
using System.Text.RegularExpressions;
namespace Daybreak.Shared.Utils;
public static partial class StringUtils
{
private const double SimilarityThreshold = 0.8;
private static readonly Regex SplitIntoWordsRegex = WordRegex();
public static int DamerauLevenshteinDistance(string s, string t)
{
var (height, width) = (s.Length + 1, t.Length + 1);
var matrix = new int[height, width];
for (var j = 0; j < height; j++) { matrix[j, 0] = j; };
for (var i = 0; i < width; i++) { matrix[0, i] = i; };
for (var j = 1; j < height; j++)
{
for (var i = 1; i < width; i++)
{
var cost = s[j - 1] == t[i - 1] ? 0 : 1;
var insertion = matrix[j, i - 1] + 1;
var deletion = matrix[j - 1, i] + 1;
var substitution = matrix[j - 1, i - 1] + cost;
var distance = Math.Min(insertion, Math.Min(deletion, substitution));
if (j > 1 && i > 1 && s[j - 1] == t[i - 2] && s[j - 2] == t[i - 1])
{
distance = Math.Min(distance, matrix[j - 2, i - 2] + cost);
}
matrix[j, i] = distance;
}
}
return matrix[height - 1, width - 1];
}
/// <summary>
/// Returns true if stringToSearch is somewhat close to searchString.
/// </summary>
/// <param name="stringToSearch"></param>
/// <param name="searchString"></param>
/// <returns>True if strings match.</returns>
public static bool MatchesSearchString(string stringToSearch, string searchString, double threshold = SimilarityThreshold)
{
if (stringToSearch.IsNullOrWhiteSpace() ||
searchString.IsNullOrWhiteSpace())
{
return false;
}
if (stringToSearch.Length > searchString.Length
? stringToSearch.Contains(searchString, StringComparison.OrdinalIgnoreCase)
: searchString.Contains(stringToSearch, StringComparison.OrdinalIgnoreCase))
{
return true;
}
var distance = MatchSearchStringScore(stringToSearch, searchString);
var similarity = 1.0 - ((double)distance / searchString.Length);
return similarity >= threshold;
}
/// <summary>
/// Returns the match string score
/// </summary>
/// <param name="stringToSearch"></param>
/// <param name="searchString"></param>
/// <returns>True if strings match.</returns>
public static int MatchSearchStringScore(string stringToSearch, string searchString)
{
return Math.Min(
DamerauLevenshteinDistance(stringToSearch.ToLower()[..Math.Min(stringToSearch.Length, searchString.Length)], searchString.ToLower()),
SplitIntoWordsRegex.Split(stringToSearch.ToLower())
.Select(word => DamerauLevenshteinDistance(word.ToLower()[..Math.Min(word.Length, searchString.Length)], searchString.ToLower())).Min());
}
[GeneratedRegex(@"\W+", RegexOptions.Compiled)]
private static partial Regex WordRegex();
}