import { Component, inject, ApplicationRef } from '@angular/core'; import { SwUpdate, VersionReadyEvent } from '@angular/service-worker'; import { filter, first } from 'rxjs/operators'; import { concat, interval, fromEvent } from 'rxjs'; import { ToastController } from '@ionic/angular'; @Component({ selector: 'app-root', templateUrl: 'app.component.html', styleUrls: ['app.component.scss'], standalone: false, }) export class AppComponent { private swUpdate = inject(SwUpdate); private appRef = inject(ApplicationRef); private toastCtrl = inject(ToastController); constructor() { this.setupUpdates(); } private async forceBypassCacheAndCheck(): Promise { try { // 1. Forza il browser mobile a controllare la rete per aggiornamenti al Service Worker nativo if ('serviceWorker' in navigator) { const registrations = await navigator.serviceWorker.getRegistrations(); for (const registration of registrations) { await registration.update(); console.log('[PWA-Update] Native Service Worker updated'); } } // 2. Forza il caricamento di ngsw.json bypassando le cache intermedie e locali await fetch(`/ngsw.json?cb=${Date.now()}`, { cache: 'no-store' }); await fetch('/ngsw.json', { cache: 'reload' }); console.log('[PWA-Update] Caches successfully busted for ngsw.json'); } catch (e) { console.warn('[PWA-Update] Failed to bust cache for ngsw.json:', e); } return await this.swUpdate.checkForUpdate(); } private setupUpdates() { if (this.swUpdate.isEnabled) { const launchTime = Date.now(); // Ricarica automaticamente se il Service Worker controller cambia per garantire la freschezza immediata if ('serviceWorker' in navigator) { navigator.serviceWorker.addEventListener('controllerchange', () => { console.log('[PWA-Update] Controller changed. Reloading page...'); window.location.reload(); }); } // 1. Sottoscrizione all'evento di versione scaricata/pronta this.swUpdate.versionUpdates .pipe(filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY')) .subscribe(async () => { const timeSinceLaunch = Date.now() - launchTime; console.log(`[PWA-Update] New version ready! Time since launch: ${timeSinceLaunch}ms`); if (timeSinceLaunch < 8000) { // Se l'applicazione รจ appena stata aperta (< 8s), la aggiorniamo ed eseguiamo il reload immediato e silenzioso console.log('[PWA-Update] Auto-activating update on startup...'); try { await this.swUpdate.activateUpdate(); console.log('[PWA-Update] Update activated successfully, reloading page...'); window.location.reload(); } catch (err) { console.error('[PWA-Update] Auto-activation failed on startup:', err); // Fallback: ricarica comunque per provare a forzare l'attivazione window.location.reload(); } } else { // Altrimenti mostriamo il prompt interattivo per evitare interruzioni improvvise console.log('[PWA-Update] Showing toast prompt for active user...'); const toast = await this.toastCtrl.create({ message: 'Nuova versione dell\'applicazione disponibile!', position: 'bottom', color: 'secondary', buttons: [ { text: 'Aggiorna', role: 'cancel', handler: () => { console.log('[PWA-Update] Activating update and reloading...'); this.swUpdate.activateUpdate().then(() => { window.location.replace(window.location.origin + window.location.pathname + '?update=' + Date.now()); }); } } ] }); await toast.present(); } }); // 2. Controllo IMMEDIATO all'avvio dell'applicazione (senza attendere lo stato isStable) console.log('[PWA-Update] Startup: Checking for PWA updates immediately...'); this.forceBypassCacheAndCheck().catch(err => { console.warn('[PWA-Update] Startup update check failed:', err); }); // 3. Attiva i controlli periodici in background solo DOPO la stabilizzazione dell'app this.appRef.isStable.pipe( filter(stable => stable), first() ).subscribe(() => { console.log('[PWA-Update] App is stable. Initializing background updates...'); // Controllo periodico ogni 60 secondi const every60Seconds$ = interval(60 * 1000); every60Seconds$.subscribe(async () => { console.log('[PWA-Update] Periodic check for updates (every 60s)...'); try { await this.forceBypassCacheAndCheck(); } catch (err) { console.warn('[PWA-Update] Periodic update check failed:', err); } }); }); // 4. Controllo quando l'utente torna sulla scheda o ripristina l'app (Visibility Change) fromEvent(document, 'visibilitychange') .pipe(filter(() => document.visibilityState === 'visible')) .subscribe(async () => { console.log('[PWA-Update] App resumed, checking for PWA updates...'); try { await this.forceBypassCacheAndCheck(); } catch (err) { console.warn('[PWA-Update] Resume update check failed:', err); } }); } } }