import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; const MIN_LOADING_TIME = 300; export interface ILoadingConfig { readonly type: 'spinner' | 'progress-bar'; readonly title?: string; readonly value?: number; readonly remainingTime?: string; } @Injectable({ providedIn: 'root' }) export class LoadingService { readonly #loadingEvent$ = new BehaviorSubject(undefined); readonly isLoading$ = this.#loadingEvent$.asObservable(); #loadingStarted = 0; #timeout?: number; start(config: ILoadingConfig = { type: 'spinner' }): void { if (this.#timeout) { clearTimeout(this.#timeout); this.#timeout = undefined; } setTimeout(() => { this.#loadingEvent$.next(config); this.#loadingStarted = new Date().getTime(); }); } update(config: ILoadingConfig): void { if (!this.#loadingEvent$.value) { return this.start(config); } this.#loadingEvent$.next(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(), ); } private _stop(): void { setTimeout(() => this.#loadingEvent$.next(undefined)); } private _stopAfter(timeout: number): void { this.#timeout = window.setTimeout(() => this._stop(), timeout); } }