import { Injectable, signal } from '@angular/core'; const MIN_LOADING_TIME = 300; export interface ILoadingConfig { readonly type: 'spinner' | 'progress-bar'; readonly title?: string; readonly value?: number; readonly remainingTime?: string; } @Injectable() export class LoadingService { readonly #loading = signal(undefined); readonly isLoading = this.#loading.asReadonly(); #loadingStarted = 0; #stopTimeout: NodeJS.Timeout | undefined; start(config: ILoadingConfig = { type: 'spinner' }): void { if (this.#stopTimeout) { clearTimeout(this.#stopTimeout); this.#stopTimeout = undefined; } setTimeout(() => { this.#loading.set(config); this.#loadingStarted = Date.now(); }); } update(config: ILoadingConfig): void { if (!this.isLoading()) { return this.start(config); } this.#loading.set(config); } stop(): void { const timeSinceStarted = new Date().getTime() - this.#loadingStarted; const remainingLoadingTime = MIN_LOADING_TIME - timeSinceStarted; return remainingLoadingTime > 0 ? this.#stopAfter(remainingLoadingTime) : this.#stop(); } loadWhile(func: Promise): void { this.start(); func.then( () => this.stop(), () => this.stop(), ); } #stop(): void { setTimeout(() => this.#loading.set(undefined)); } #stopAfter(clearAfter: number): void { this.#stopTimeout = setTimeout(() => this.#stop(), clearAfter); } }