Crunchy-Downloader/CRD/Utils/QueueManagement/UiMutationQueue.cs
Elwador d9813191ad - Added **Global Pause button** for the download queue [#418](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/418)
- Added **fallback for sync failures** [#407](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/407)
- Added **history setting** to remove non-existent series/episodes on refresh [#420](https://github.com/Crunchy-DL/Crunchy-Downloader/issues/420)
- Added **movies to history**
- Added **queue persistence**
- Changed **download item state handling**
- Changed **download item removal processing**
- Made small changes to **font detection**
- Changed **rate limit error handling**
- Fixed issue where **files were not always cleaned up** for removed downloads
- Fixed **crash when the queue list was modified**
- Fixed **changelog parsing** not handling versions like `vX.X.X.X`, which caused changes to be re-added on every restart
2026-04-20 15:40:58 +02:00

79 lines
No EOL
2 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using Avalonia.Threading;
namespace CRD.Utils.QueueManagement;
public sealed class UiMutationQueue{
private readonly object syncLock = new();
private readonly Queue<Action> pendingMutations = new();
private readonly Dispatcher dispatcher;
private readonly DispatcherPriority priority;
private bool isProcessing;
private int pumpScheduled;
public UiMutationQueue()
: this(null, DispatcherPriority.Background){
}
public UiMutationQueue(
Dispatcher? dispatcher,
DispatcherPriority priority){
this.dispatcher = dispatcher ?? Dispatcher.UIThread;
this.priority = priority;
}
public void Enqueue(Action mutation){
if (mutation == null)
throw new ArgumentNullException(nameof(mutation));
lock (syncLock){
pendingMutations.Enqueue(mutation);
}
if (Interlocked.CompareExchange(ref pumpScheduled, 1, 0) != 0)
return;
dispatcher.Post(ProcessPendingMutations, priority);
}
private void ProcessPendingMutations(){
if (isProcessing)
return;
try{
isProcessing = true;
while (true){
Action? mutation;
lock (syncLock){
mutation = pendingMutations.Count > 0
? pendingMutations.Dequeue()
: null;
}
if (mutation is null)
break;
mutation();
}
} finally{
isProcessing = false;
Interlocked.Exchange(ref pumpScheduled, 0);
bool hasPending;
lock (syncLock){
hasPending = pendingMutations.Count > 0;
}
if (hasPending &&
Interlocked.CompareExchange(ref pumpScheduled, 1, 0) == 0){
dispatcher.Post(ProcessPendingMutations, priority);
}
}
}
}