//-----------------------------------------------------------------------
//
// Copyright (c) aliasvault. All rights reserved.
// Licensed under the AGPLv3 license. See LICENSE.md file in the project root for full license information.
//
//-----------------------------------------------------------------------
namespace AliasVault.Client.Main.Services;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
///
/// Service to manage loading states with a minimum duration.
///
public class MinDurationLoadingService : IDisposable
{
private readonly ConcurrentDictionary _loadingStates = [];
///
/// Call this to start the loading state for a given key.
///
/// The key to set the loading state for.
/// The minimum duration in milliseconds that must pass before the loading state can be considered finished.
/// An optional callback to invoke when the state changes.
public void StartLoading(string key, int minDurationMs, Action? onStateChanged = null)
{
_loadingStates[key] = (DateTime.UtcNow, minDurationMs, true);
onStateChanged?.Invoke();
}
///
/// Call this to finish the loading state for a given key, ensuring a minimum duration is respected.
///
/// The key to clear the loading state for.
/// An optional callback to invoke when the state changes.
public void FinishLoading(string key, Action? onStateChanged = null)
{
if (!_loadingStates.TryGetValue(key, out var state) || !state.IsLoading)
{
// Nothing to do
return;
}
var elapsed = (DateTime.UtcNow - state.StartTime).TotalMilliseconds;
var remaining = Math.Max(0, state.MinDurationMs - elapsed);
Task.Run(async () =>
{
if (remaining > 0)
{
await Task.Delay((int)remaining);
}
if (_loadingStates.TryGetValue(key, out var currentState) && currentState.IsLoading)
{
_loadingStates[key] = (currentState.StartTime, currentState.MinDurationMs, false);
onStateChanged?.Invoke();
}
});
}
///
/// Checks if a given key is currently in a loading state.
///
/// The key to check the loading state for.
/// True if the key is loading, false otherwise.
public bool IsLoading(string key)
{
return _loadingStates.TryGetValue(key, out var state) && state.IsLoading;
}
///
/// Disposes of the service.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Protected implementation of Dispose pattern.
///
/// True if called from Dispose, false if called from finalizer.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_loadingStates.Clear();
}
}
}