| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 |
- 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<typeof setTimeout> | undefined;
- private hideTimer: ReturnType<typeof setTimeout> | 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);
- };
- }
- }
|