Add Git overlay, operation tools, and virtualized preview so large folders stay responsive.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-24 15:04:04 +02:00
parent 9bf451932f
commit a3c54bbb03
127 changed files with 14748 additions and 633 deletions

View File

@@ -0,0 +1,233 @@
namespace Explorer.Application;
public readonly record struct ThumbnailKey(string Path, long ModifiedTicks, int PixelWidth)
{
public static ThumbnailKey From(string path, DateTimeOffset? modifiedUtc, int pixelWidth)
=> new(path, modifiedUtc?.UtcTicks ?? 0, pixelWidth);
}
public readonly record struct ThumbnailJob(
ThumbnailKey Key,
int Rank,
int Generation);
public readonly record struct ThumbnailSchedulerStats(
int Generation,
int Window,
int Pending,
int InFlight,
int Requested,
int CacheHits,
int Generated,
int Cancelled,
int Failed);
public sealed class ThumbnailScheduler
{
public const int DefaultConcurrency = 2;
public const int DefaultPixelWidth = 128;
public const int MaxPending = 96;
public const int PrefetchItems = 24;
private readonly object _gate = new();
private readonly List<ThumbnailJob> _window = [];
private readonly HashSet<ThumbnailKey> _windowKeys = [];
private readonly HashSet<ThumbnailKey> _inFlight = [];
private readonly HashSet<ThumbnailKey> _cached = [];
private int _generation;
private bool _enabled;
private int _requested;
private int _cacheHits;
private int _generated;
private int _cancelled;
private int _failed;
public int Generation
{
get { lock (_gate) return _generation; }
}
public int InFlight
{
get { lock (_gate) return _inFlight.Count; }
}
public void Reset(int generation)
{
lock (_gate)
{
_cancelled += _window.Count + _inFlight.Count;
_generation = generation;
_window.Clear();
_windowKeys.Clear();
_inFlight.Clear();
}
}
public void SetEnabled(bool enabled)
{
lock (_gate)
{
_enabled = enabled;
if (enabled)
{
return;
}
_cancelled += _window.Count + _inFlight.Count;
_window.Clear();
_windowKeys.Clear();
_inFlight.Clear();
}
}
public bool IsCached(ThumbnailKey key)
{
lock (_gate)
{
return _cached.Contains(key);
}
}
public void MarkCached(ThumbnailKey key)
{
lock (_gate)
{
_cached.Add(key);
}
}
public void RecordCacheHit()
{
lock (_gate)
{
_cacheHits++;
_requested++;
}
}
public IReadOnlyList<ThumbnailJob> SetWindow(int generation, IReadOnlyList<ThumbnailJob> jobs)
{
ArgumentNullException.ThrowIfNull(jobs);
lock (_gate)
{
if (generation != _generation || !_enabled)
{
_cancelled += jobs.Count;
return [];
}
var next = jobs
.Where(j => j.Generation == _generation)
.GroupBy(j => j.Key)
.Select(g => g.OrderBy(j => j.Rank).First())
.OrderBy(j => j.Rank)
.Take(MaxPending)
.ToList();
var nextKeys = next.Select(j => j.Key).ToHashSet();
foreach (var previous in _window)
{
if (!nextKeys.Contains(previous.Key))
{
_cancelled++;
}
}
foreach (var key in _inFlight.ToArray())
{
if (!nextKeys.Contains(key))
{
_inFlight.Remove(key);
_cancelled++;
}
}
_window.Clear();
_window.AddRange(next);
_windowKeys.Clear();
foreach (var job in next)
{
_windowKeys.Add(job.Key);
}
_requested += next.Count(j => !_cached.Contains(j.Key) && !_inFlight.Contains(j.Key));
return next;
}
}
public bool TryTake(out ThumbnailJob job)
{
lock (_gate)
{
if (!_enabled)
{
job = default;
return false;
}
foreach (var candidate in _window)
{
if (_cached.Contains(candidate.Key) || _inFlight.Contains(candidate.Key))
{
continue;
}
_inFlight.Add(candidate.Key);
job = candidate;
return true;
}
}
job = default;
return false;
}
public bool IsCurrent(ThumbnailJob job)
{
lock (_gate)
{
return _enabled
&& job.Generation == _generation
&& _windowKeys.Contains(job.Key);
}
}
public void Complete(ThumbnailJob job, bool generated, bool failed)
{
lock (_gate)
{
_inFlight.Remove(job.Key);
if (failed)
{
_failed++;
_cached.Add(job.Key);
return;
}
if (generated)
{
_generated++;
_cached.Add(job.Key);
}
}
}
public ThumbnailSchedulerStats Snapshot()
{
lock (_gate)
{
var pending = _window.Count(j => !_cached.Contains(j.Key) && !_inFlight.Contains(j.Key));
return new ThumbnailSchedulerStats(
_generation,
_window.Count,
pending,
_inFlight.Count,
_requested,
_cacheHits,
_generated,
_cancelled,
_failed);
}
}
}