public bool HasChanges(Achievement achievement) { return Distance != achievement.Distance || Duration != achievement.Duration || Speed != achievement.Speed || Repetitions != achievement.Repetitions || Weight != achievement.Weight || CommentText != achievement.CommentText || IsPropped != achievement.IsPropped; }
public async Task<IEnumerable<Achievement>> Execute(Workout workout) { var achievements = new List<Achievement>(); foreach (var activity in workout.Activities .Where(activity => activity.Group != null) .GroupBy(activity => new {activity.Group, activity.Name}) .Select(group => new {group.Key.Group, group.Key.Name, Sets = group.SelectMany(activity => activity.Sets).ToList()}) .Where(activity => !activity.Sets.Any(set => set.IsPr))) { var category = _grouping.GetGroupCategory(activity.Group); if (category == null) { continue; } if (category == ActivityCategory.Weights) { var max = activity.Sets .OrderByDescending(set => set.Weight) .ThenByDescending(set => set.Repetitions) .FirstOrDefault(); if (max == null || (max.Weight == null && max.Repetitions == null)) { continue; } var fromDate = workout.Date.AddYears(-1); var lastYearMax = await _database.Single<dynamic>( "select top 1 s.[Weight], s.[Repetitions] " + "from [Workout] w, [Activity] a, [Set] s " + "where w.[Id] = a.[WorkoutId] " + "and a.[Id] = s.[ActivityId] " + "and w.[UserId] = @UserId " + "and w.[Date] < @fromDate " + "and a.[Name] = @Name " + "order by s.[Weight] desc, s.[Repetitions] desc", new {workout.UserId, fromDate, activity.Name}); if (lastYearMax == null || max.Weight > lastYearMax.Weight || (max.Weight == lastYearMax.Weight && max.Repetitions > lastYearMax.Repetitions) || max.Weight*2 <= lastYearMax.Weight) { continue; } var thisYearMax = await _database.Single<dynamic>( "select top 1 s.[Weight], s.[Repetitions] " + "from [Workout] w, [Activity] a, [Set] s " + "where w.[Id] = a.[WorkoutId] " + "and a.[Id] = s.[ActivityId] " + "and w.[UserId] = @UserId " + "and w.[Date] >= @fromDate " + "and w.[Date] < @Date " + "and a.[Name] = @Name " + "and s.[Weight] " + (max.Weight != null ? ">= @Weight" : "is null") + " " + "order by s.[Weight] desc, s.[Repetitions] desc", new {workout.UserId, fromDate, workout.Date, activity.Name, max.Weight}); if (thisYearMax != null && (max.Weight < thisYearMax.Weight || max.Repetitions <= thisYearMax.Repetitions)) { continue; } var achievement = new Achievement { Type = "ComebackRecord", Activity = activity.Name, CommentText = $"1 year {activity.Name} comeback record: " }; if (max.Weight == null) { achievement.Repetitions = max.Repetitions; achievement.CommentText += max.Repetitions.FormatRepetitions(); } else { achievement.Weight = max.Weight; achievement.CommentText += max.Weight.FormatWeight(max.IsImperial); if (thisYearMax != null && max.Weight == thisYearMax.Weight) { achievement.Repetitions = max.Repetitions; achievement.CommentText += " for " + max.Repetitions.FormatRepetitions(); } } achievements.Add(achievement); } else { string column; switch (category) { case ActivityCategory.Cardio: column = "Distance"; break; case ActivityCategory.Bodyweight: column = "Repetitions"; break; case ActivityCategory.Sports: column = "Duration"; break; default: throw new ArgumentOutOfRangeException(); } var max = activity.Sets .Select(set => { switch (category) { case ActivityCategory.Cardio: return new {Value = set.Distance, set.IsImperial}; case ActivityCategory.Bodyweight: return new {Value = set.Repetitions, set.IsImperial}; case ActivityCategory.Sports: return new {Value = set.Duration, set.IsImperial}; default: throw new ArgumentOutOfRangeException(); } }) .OrderByDescending(set => set.Value) .FirstOrDefault(); if (max?.Value == null) { continue; } var fromDate = workout.Date.AddYears(-1); var lastYearMax = await _database.Single<decimal?>( "select max(s.[" + column + "]) " + "from [Workout] w, [Activity] a, [Set] s " + "where w.[Id] = a.[WorkoutId] " + "and a.[Id] = s.[ActivityId] " + "and w.[UserId] = @UserId " + "and w.[Date] < @fromDate " + "and a.[Name] = @Name", new {workout.UserId, fromDate, activity.Name}); if (lastYearMax == null || max.Value > lastYearMax || max.Value*2 <= lastYearMax) { continue; } var thisYearCount = await _database.Single<int>( "select count(*) " + "from [Workout] w, [Activity] a, [Set] s " + "where w.[Id] = a.[WorkoutId] " + "and a.[Id] = s.[ActivityId] " + "and w.[UserId] = @UserId " + "and w.[Date] >= @fromDate " + "and w.[Date] < @Date " + "and a.[Name] = @Name " + "and s.[" + column + "] >= @Value", new {workout.UserId, fromDate, workout.Date, activity.Name, max.Value}); if (thisYearCount > 0) { continue; } var achievement = new Achievement { Type = "ComebackRecord", Activity = activity.Name }; string formattedValue; switch (category) { case ActivityCategory.Cardio: achievement.Distance = max.Value; formattedValue = max.Value.FormatDistance(max.IsImperial); break; case ActivityCategory.Bodyweight: achievement.Repetitions = max.Value; formattedValue = max.Value.FormatRepetitions(); break; case ActivityCategory.Sports: achievement.Duration = max.Value; formattedValue = max.Value.FormatDuration(); break; default: throw new ArgumentOutOfRangeException(); } achievement.CommentText = $"1 year {activity.Name} comeback record: {formattedValue}"; achievements.Add(achievement); } } return achievements; }
public async Task<IEnumerable<Achievement>> Execute(Workout workout) { var achievements = new List<Achievement>(); foreach (var group in workout.Activities.GroupBy(activity => activity.Group).Where(group => group.Key != null)) { var category = _grouping.GetGroupCategory(group.Key); if (category == null) { continue; } int threshold; if (!Thresholds.TryGetValue(group.Key, out threshold)) { switch (category) { case ActivityCategory.Cardio: threshold = 500; break; case ActivityCategory.Sports: threshold = 100; break; default: threshold = 2000; break; } } string column; switch (category) { case ActivityCategory.Cardio: column = "Distance"; threshold *= 1000; break; case ActivityCategory.Sports: column = "Duration"; threshold *= 3600; break; default: column = "Repetitions"; break; } var previousSum = await _database.Single<decimal?>( "select sum([" + column + "]) " + "from [Workout] w, [Activity] a, [Set] s " + "where w.[Id] = a.[WorkoutId] " + "and a.[Id] = s.[ActivityId] " + "and w.[UserId] = @UserId " + "and w.[Date] < @Date " + "and a.[Group] = @Key", new {workout.UserId, workout.Date, group.Key}); if (previousSum == null) { continue; } var sum = group.SelectMany(activity => activity.Sets) .Sum(set => { switch (category) { case ActivityCategory.Cardio: return set.Distance; case ActivityCategory.Sports: return set.Duration; default: return set.Repetitions; } }) + previousSum; if (sum < threshold) { continue; } previousSum = Math.Floor(previousSum.Value/threshold)*threshold; sum = Math.Floor(sum.Value/threshold)*threshold; if (sum == previousSum) { continue; } var achievement = new Achievement { Type = "LifetimeMilestone", Group = group.Key }; string formattedValue; switch (category) { case ActivityCategory.Cardio: achievement.Distance = sum; formattedValue = sum.FormatDistance(); break; case ActivityCategory.Sports: achievement.Duration = sum; formattedValue = sum.FormatDuration(); break; default: achievement.Repetitions = sum; formattedValue = sum.FormatRepetitions(); break; } achievement.CommentText = $"Lifetime {group.Key} milestone: {formattedValue}"; achievements.Add(achievement); } return achievements; }
public async Task<IEnumerable<Achievement>> Execute(Workout workout) { var achievements = new List<Achievement>(); foreach (var group in workout.Activities.GroupBy(activity => activity.Group).Where(group => group.Key != null)) { var category = _grouping.GetGroupCategory(group.Key); if (category == null) { continue; } var sets = group.SelectMany(activity => activity.Sets).ToList(); if (sets.Count <= 1) { continue; } var sum = sets.Sum(set => { switch (category) { case ActivityCategory.Cardio: return set.Distance; case ActivityCategory.Sports: return set.Duration; default: return set.Repetitions; } }); if (sum == 0 || (category == ActivityCategory.Cardio && sum < 1000)) { continue; } string column; switch (category) { case ActivityCategory.Cardio: column = "Distance"; break; case ActivityCategory.Sports: column = "Duration"; break; default: column = "Repetitions"; break; } var previousMax = await _database.Single<decimal?>( "select max([Value]) " + "from ( " + " select sum(s.[" + column + "]) [Value] " + " from [Workout] w, [Activity] a, [Set] s " + " where w.[Id] = a.[WorkoutId] " + " and a.[Id] = s.[ActivityId] " + " and w.[UserId] = @UserId " + " and w.[Date] < @Date " + " and a.[Group] = @Key " + " group by w.[Id] " + ") [x]", new {workout.UserId, workout.Date, group.Key}); if ((previousMax ?? 0) == 0 || sum <= previousMax) { continue; } var achievement = new Achievement { Type = "DailyRecord", Group = group.Key }; string formattedValue; switch (category) { case ActivityCategory.Cardio: achievement.Distance = sum; var lookup = sets.ToLookup(set => set.IsImperial); formattedValue = sum.FormatDistance(lookup[true].Count() > lookup[false].Count()); break; case ActivityCategory.Sports: achievement.Duration = sum; formattedValue = sum.FormatDuration(); break; default: achievement.Repetitions = sum; formattedValue = sum.FormatRepetitions(); break; } achievement.CommentText = $"Daily {group.Key} record: {formattedValue}"; achievements.Add(achievement); } return achievements; }