//----------------------------------------------------------------------- // // 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(); } } }