diff --git a/LiftLog.Lib/Models/BlueprintModels.cs b/LiftLog.Lib/Models/BlueprintModels.cs index 7bc9c432..ec5b6637 100644 --- a/LiftLog.Lib/Models/BlueprintModels.cs +++ b/LiftLog.Lib/Models/BlueprintModels.cs @@ -49,34 +49,36 @@ public record ExerciseBlueprint( string Notes ); -public sealed record KeyedExerciseBlueprint : IEquatable +public record KeyedExerciseBlueprint(string Name, int Sets, int RepsPerSet) { - private readonly string normalizedName = string.Empty; - public string Name { get; } + public static implicit operator KeyedExerciseBlueprint(ExerciseBlueprint e) => + new(e.Name, e.Sets, e.RepsPerSet); - public KeyedExerciseBlueprint(string name) + public class NormalizedNameOnlyEqualityComparer : IEqualityComparer { - Name = name; - normalizedName = NormalizeName(name); - } - - public static implicit operator KeyedExerciseBlueprint(ExerciseBlueprint e) => new(e.Name); + public static readonly NormalizedNameOnlyEqualityComparer Instance = new(); - public bool Equals(KeyedExerciseBlueprint? other) => other?.normalizedName == normalizedName; + public bool Equals(KeyedExerciseBlueprint? x, KeyedExerciseBlueprint? y) => + NormalizeName(x?.Name) == NormalizeName(y?.Name); - public override int GetHashCode() => normalizedName.GetHashCode(); + public int GetHashCode(KeyedExerciseBlueprint obj) => NormalizeName(obj.Name).GetHashCode(); - private static string NormalizeName(string name) - { - var lowerName = name.ToLower().Trim().Replace("flies", "flys").Replace("flyes", "flys"); - var withoutPlural = lowerName switch + private static string NormalizeName(string? name) { - string when lowerName.EndsWith("es") => lowerName[..^2], - string when lowerName.EndsWith('s') => lowerName[..^1], - _ => lowerName, - }; - - return withoutPlural; + if (name is null) + { + return string.Empty; + } + var lowerName = name.ToLower().Trim().Replace("flies", "flys").Replace("flyes", "flys"); + var withoutPlural = lowerName switch + { + string when lowerName.EndsWith("es") => lowerName[..^2], + string when lowerName.EndsWith('s') => lowerName[..^1], + _ => lowerName, + }; + + return withoutPlural; + } } } diff --git a/LiftLog.Ui/Services/ProgressRepository.cs b/LiftLog.Ui/Services/ProgressRepository.cs index 48a2192d..1338576d 100644 --- a/LiftLog.Ui/Services/ProgressRepository.cs +++ b/LiftLog.Ui/Services/ProgressRepository.cs @@ -167,7 +167,10 @@ public ValueTask< )) .ToAsyncEnumerable() ) - .GroupBy(x => (KeyedExerciseBlueprint)x.RecordedExercise.Blueprint) + .GroupBy( + x => (KeyedExerciseBlueprint)x.RecordedExercise.Blueprint, + KeyedExerciseBlueprint.NormalizedNameOnlyEqualityComparer.Instance + ) .ToImmutableDictionaryAwaitAsync( x => ValueTask.FromResult(x.Key), async x => await x.Take(maxRecordsPerExercise).ToImmutableListValueAsync() diff --git a/LiftLog.Ui/Store/Stats/StatsEffects.cs b/LiftLog.Ui/Store/Stats/StatsEffects.cs index c8ae9835..8d8b3b67 100644 --- a/LiftLog.Ui/Store/Stats/StatsEffects.cs +++ b/LiftLog.Ui/Store/Stats/StatsEffects.cs @@ -73,7 +73,10 @@ state.Value.OverallViewSessionName is null ex )) ) - .GroupBy(x => new KeyedExerciseBlueprint(x.RecordedExercise.Blueprint.Name)) + .GroupBy( + x => (KeyedExerciseBlueprint)x.RecordedExercise.Blueprint, + KeyedExerciseBlueprint.NormalizedNameOnlyEqualityComparer.Instance + ) .Select(CreateExerciseStatistic) .ToImmutableList(); @@ -103,7 +106,10 @@ state.Value.OverallViewSessionName is null var exerciseMostTimeSpent = sessions .SelectMany(x => x.RecordedExercises) .Where(x => x.LastRecordedSet?.Set is not null) - .GroupBy(x => new KeyedExerciseBlueprint(x.Blueprint.Name)) + .GroupBy( + x => (KeyedExerciseBlueprint)x.Blueprint, + KeyedExerciseBlueprint.NormalizedNameOnlyEqualityComparer.Instance + ) .Select(x => new TimeSpentExercise( x.First().Blueprint.Name, x.Select(x => x.TimeSpent).Aggregate((a, b) => a + b)