Adaptive delay for selecteds children

This commit is contained in:
2023-07-26 10:24:03 +02:00
parent e70bc3643a
commit ba1210b2c4

View File

@@ -6,7 +6,9 @@ namespace FileTime.App.Core.Services;
public sealed class RefreshSmoothnessCalculator : IRefreshSmoothnessCalculator, INotifyPropertyChanged public sealed class RefreshSmoothnessCalculator : IRefreshSmoothnessCalculator, INotifyPropertyChanged
{ {
private const int MaxSampleTimeInSeconds = 10; private const int MaxSampleTimeInSeconds = 10;
private const int MaxDelayBetweenRefreshes = 400; private const int SampleWindowInMilliseconds = 1000;
private const int MaxDelayBetweenRefreshes = 600;
private const int MinDelayBetweenRefreshes = 10;
private readonly TimeSpan _maxDelay = TimeSpan.FromSeconds(MaxSampleTimeInSeconds); private readonly TimeSpan _maxDelay = TimeSpan.FromSeconds(MaxSampleTimeInSeconds);
private readonly TimeSpan _defaultRefreshDelay = TimeSpan.FromMilliseconds(200); private readonly TimeSpan _defaultRefreshDelay = TimeSpan.FromMilliseconds(200);
private readonly Queue<DateTime> _changeTimes = new(); private readonly Queue<DateTime> _changeTimes = new();
@@ -65,46 +67,37 @@ public sealed class RefreshSmoothnessCalculator : IRefreshSmoothnessCalculator,
CleanList(now); CleanList(now);
var queue = new Queue<DateTime>(_changeTimes); var queue = new Queue<DateTime>(_changeTimes);
var values = new List<(double score, double weight)>(queue.Count - 1); var segments = (int)Math.Ceiling((double)MaxSampleTimeInSeconds * 1000 / SampleWindowInMilliseconds);
Span<int> segmentElementCounts = stackalloc int[segments];
var previousChangeTime = queue.Dequeue();
var biggestDelay = now - previousChangeTime;
while (queue.Count > 0) while (queue.Count > 0)
{ {
var changeTime = queue.Dequeue(); var item = queue.Dequeue();
var segment = segments - 1 - (int)((now - item).TotalMilliseconds / SampleWindowInMilliseconds);
var (score, weight) = CalculateScoreAndWeight(changeTime, previousChangeTime, biggestDelay); segmentElementCounts[segment]++;
values.Add((score, weight));
previousChangeTime = changeTime;
} }
var combinedScore = values.Sum(i => i.weight * i.score) / values.Sum(i => i.weight); var weightSum = 0d;
var score = 0d;
var normalizedCombinedScore = (combinedScore * 1.2 - 0.1); //Note: This might not be the best algorithm to calculate the delay, but works okay.
//Note: I had an algorithm in mind that uses the delta between neighbour times and and delta between a time and now, but I couldn't implement it.
if (normalizedCombinedScore < 0) normalizedCombinedScore = 0; //Note: If you are good at math and have a better algorithm, please feel free to implement it/create an issue with it.
else if (normalizedCombinedScore > 1) normalizedCombinedScore = 1; for (var i = 0; i < segments; i++)
var finalDelay = normalizedCombinedScore * MaxDelayBetweenRefreshes;
RefreshDelay = TimeSpan.FromMilliseconds(finalDelay);
(double score, double weight) CalculateScoreAndWeight(DateTime changeTime, DateTime previousChangeTime, TimeSpan biggestDelay)
{ {
var delayToPrevious = changeTime - previousChangeTime; var weight = Math.Pow(i, 2);
var delayToNow = now - changeTime; weightSum += weight;
var pressCount = segmentElementCounts[i];
var toNowRatio = (delayToNow.TotalMilliseconds / biggestDelay.TotalMilliseconds); //Note: we want the minimum delay even if the user pressed only once in a segment
var score = 1 - (delayToPrevious.TotalMilliseconds / biggestDelay.TotalMilliseconds); if (pressCount > 0) pressCount--;
var weight = 1 - toNowRatio; score += pressCount * weight;
if (score < 0) score = 0;
else if (score > 1) score = 1;
return (score, weight);
} }
const double fraction = (double)(MaxDelayBetweenRefreshes - MinDelayBetweenRefreshes) / 4;
var weightedAvg = weightSum == 0 ? _defaultRefreshDelay.TotalMilliseconds : Math.Round(score / weightSum);
var finalDelay = (weightedAvg * fraction) + MinDelayBetweenRefreshes;
finalDelay = finalDelay > MaxDelayBetweenRefreshes ? MaxDelayBetweenRefreshes : finalDelay;
RefreshDelay = TimeSpan.FromMilliseconds(finalDelay);
} }
} }