4e85a6cccc
* add base revit 26 projects * fix up cef replacement * fix up revit 2026 events * add revit events * fixes for revit 26 * use right version of DI for Revit26 * add Revit26 to local * fmt * use visual studio to fix slns * Add revit to installer constants * move webview stuff to 2026 specific area to avoid build issues * update locks * Revit 2026 wants to invoke scripts with RevitTask. Abstract RevitTask * fmt * fix project copying * use 3.2 SDK * fix build * Revit 2025 is now CEF vulnerable * add SendProgress to not overload revit context * update Revit 26 lock files * update locks --------- Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com>
80 lines
2.5 KiB
C#
80 lines
2.5 KiB
C#
using System.Collections.Concurrent;
|
|
using Speckle.Connectors.Common.Operations;
|
|
using Speckle.Connectors.DUI.Bridge;
|
|
using Speckle.Connectors.DUI.Models.Card;
|
|
using Speckle.InterfaceGenerator;
|
|
|
|
namespace Speckle.Connectors.DUI.Bindings;
|
|
|
|
/// <summary>
|
|
/// Debouncing progress for every %1 update for UI.
|
|
/// This class requires a specific bridge in its binding, so registering it will create random bridge which we don't want to.
|
|
/// </summary>
|
|
[GenerateAutoInterface]
|
|
public class OperationProgressManager : IOperationProgressManager
|
|
{
|
|
private class NonUIThreadProgress<T>(Action<T> handler) : IProgress<T>
|
|
{
|
|
public void Report(T value) => handler(value);
|
|
}
|
|
|
|
private const string SET_MODEL_PROGRESS_UI_COMMAND_NAME = "setModelProgress";
|
|
private static readonly ConcurrentDictionary<string, (DateTime lastCallTime, string status)> s_lastProgressValues =
|
|
new();
|
|
private const int THROTTLE_INTERVAL_MS = 200;
|
|
|
|
public IProgress<CardProgress> CreateOperationProgressEventHandler(
|
|
IBrowserBridge bridge,
|
|
string modelCardId,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var progress = new NonUIThreadProgress<CardProgress>(args =>
|
|
{
|
|
SetModelProgress(
|
|
bridge,
|
|
modelCardId,
|
|
new ModelCardProgress(modelCardId, args.Status, args.Progress),
|
|
cancellationToken
|
|
);
|
|
});
|
|
return progress;
|
|
}
|
|
|
|
public void SetModelProgress(
|
|
IBrowserBridge bridge,
|
|
string modelCardId,
|
|
ModelCardProgress progress,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
if (cancellationToken.IsCancellationRequested)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!s_lastProgressValues.TryGetValue(modelCardId, out (DateTime, string) t))
|
|
{
|
|
t.Item1 = DateTime.Now;
|
|
s_lastProgressValues[modelCardId] = (t.Item1, progress.Status);
|
|
// Since it's the first time we get a call for this model card, we should send it out
|
|
SendProgress(bridge, modelCardId, progress);
|
|
return;
|
|
}
|
|
|
|
var currentTime = DateTime.Now;
|
|
var elapsedMs = (currentTime - t.Item1).Milliseconds;
|
|
|
|
if (elapsedMs < THROTTLE_INTERVAL_MS && t.Item2 == progress.Status)
|
|
{
|
|
return;
|
|
}
|
|
Console.WriteLine($"Progress: {progress.Status} - {progress.Progress}");
|
|
s_lastProgressValues[modelCardId] = (currentTime, progress.Status);
|
|
SendProgress(bridge, modelCardId, progress);
|
|
}
|
|
|
|
private static void SendProgress(IBrowserBridge bridge, string modelCardId, ModelCardProgress progress) =>
|
|
bridge.SendProgress(SET_MODEL_PROGRESS_UI_COMMAND_NAME, new { modelCardId, progress });
|
|
}
|