import { Injectable, signal } from '@angular/core'; const SHOW_DELAY_MS = 180; const MIN_VISIBLE_MS = 360; /** Coordinates one unobtrusive loading indicator for all admin HttpClient requests. */ @Injectable({ providedIn: 'root' }) export class AdminRequestActivityService { private readonly pendingState = signal(0); private readonly visibleState = signal(false); private showTimer: ReturnType | undefined; private hideTimer: ReturnType | undefined; private shownAt = 0; readonly pending = this.pendingState.asReadonly(); readonly visible = this.visibleState.asReadonly(); begin(): () => void { if (this.hideTimer) { clearTimeout(this.hideTimer); this.hideTimer = undefined; } this.pendingState.update(count => count + 1); if (!this.visibleState() && !this.showTimer) { this.showTimer = setTimeout(() => { this.showTimer = undefined; if (this.pendingState() > 0) { this.shownAt = Date.now(); this.visibleState.set(true); } }, SHOW_DELAY_MS); } let completed = false; return () => { if (completed) return; completed = true; this.pendingState.update(count => Math.max(0, count - 1)); if (this.pendingState() > 0) return; if (this.showTimer) { clearTimeout(this.showTimer); this.showTimer = undefined; } if (!this.visibleState()) return; const delay = Math.max(0, MIN_VISIBLE_MS - (Date.now() - this.shownAt)); this.hideTimer = setTimeout(() => { this.hideTimer = undefined; if (this.pendingState() === 0) this.visibleState.set(false); }, delay); }; } }