vers. 2.6.0
This commit is contained in:
@@ -1043,11 +1043,75 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (homeNav) homeNav.style.display = 'block';
|
||||
};
|
||||
|
||||
/**
|
||||
* Gestione dello stato Offline
|
||||
*/
|
||||
function initOfflineDetection() {
|
||||
let offlineOverlay = document.getElementById('offlineOverlay');
|
||||
if (!offlineOverlay) {
|
||||
offlineOverlay = document.createElement('div');
|
||||
offlineOverlay.id = 'offlineOverlay';
|
||||
offlineOverlay.className = 'offline-overlay';
|
||||
offlineOverlay.innerHTML = `
|
||||
<div class="offline-content">
|
||||
<span class="material-icons offline-icon">wifi_off</span>
|
||||
<h2 class="offline-title">Nessuna Connessione</h2>
|
||||
<p class="offline-desc">Sembra che tu sia offline. Controlla la tua connessione internet per continuare ad ascoltare RPIGroup Play.</p>
|
||||
<button class="offline-btn" id="offlineRetryBtn">
|
||||
<span class="material-icons">refresh</span> Riprova
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(offlineOverlay);
|
||||
|
||||
const retryBtn = document.getElementById('offlineRetryBtn');
|
||||
if (retryBtn) {
|
||||
retryBtn.addEventListener('click', function() {
|
||||
retryBtn.disabled = true;
|
||||
retryBtn.innerHTML = '<span class="material-icons spinner-offline" style="animation: spin 1s infinite linear; vertical-align: middle;">sync</span> Verifica in corso...';
|
||||
|
||||
fetch(BASE_PATH + '/robots.txt', { cache: 'no-store', mode: 'no-cors' })
|
||||
.then(() => {
|
||||
offlineOverlay.classList.remove('active');
|
||||
window.location.reload();
|
||||
})
|
||||
.catch(() => {
|
||||
setTimeout(() => {
|
||||
retryBtn.disabled = false;
|
||||
retryBtn.innerHTML = '<span class="material-icons">refresh</span> Riprova';
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function showOfflineOverlay() {
|
||||
offlineOverlay.classList.add('active');
|
||||
}
|
||||
|
||||
function hideOfflineOverlay() {
|
||||
offlineOverlay.classList.remove('active');
|
||||
}
|
||||
|
||||
window.addEventListener('offline', showOfflineOverlay);
|
||||
window.addEventListener('online', () => {
|
||||
hideOfflineOverlay();
|
||||
console.log('Dispositivo tornato online. Ripristino...');
|
||||
});
|
||||
|
||||
if (!navigator.onLine) {
|
||||
showOfflineOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inizializzazione principale
|
||||
*/
|
||||
function init() {
|
||||
console.log('Inizializzazione app...');
|
||||
|
||||
// Rilevamento stato offline
|
||||
initOfflineDetection();
|
||||
|
||||
setupOpenAppButton();
|
||||
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/**
|
||||
* PWA Install and Service Worker Helper
|
||||
* Powered by Antigravity AI
|
||||
*/
|
||||
|
||||
(function () {
|
||||
const BASE_PATH = window.BASE_PATH || '';
|
||||
|
||||
// Register Service Worker
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${BASE_PATH}/sw.js`;
|
||||
navigator.serviceWorker.register(swUrl)
|
||||
.then((registration) => {
|
||||
console.log('[PWA] Service Worker registrato con successo:', registration.scope);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[PWA] Registrazione Service Worker fallita:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Detectors
|
||||
const isStandalone = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true;
|
||||
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
||||
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
|
||||
// Se l'app viene aperta in modalità standalone (PWA) su desktop, reindirizza all'interno dell'app
|
||||
if (isStandalone && !isMobile) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (!urlParams.has('app') || urlParams.get('app') !== 'true') {
|
||||
const currentPath = window.location.pathname;
|
||||
const pathWithoutBase = currentPath.replace(BASE_PATH, '').replace(/^\//, '');
|
||||
const redirectParam = pathWithoutBase ? '&redirect=' + encodeURIComponent(pathWithoutBase) : '';
|
||||
window.location.href = BASE_PATH + '/?app=true' + redirectParam;
|
||||
}
|
||||
}
|
||||
|
||||
// Global variables
|
||||
window.deferredPrompt = null;
|
||||
|
||||
// Check if banner was dismissed in the last 7 days
|
||||
function isBannerDismissed() {
|
||||
const dismissedTime = localStorage.getItem('pwa-banner-dismissed');
|
||||
if (!dismissedTime) return false;
|
||||
|
||||
const sevenDays = 7 * 24 * 60 * 60 * 1000;
|
||||
return (Date.now() - parseInt(dismissedTime, 10)) < sevenDays;
|
||||
}
|
||||
|
||||
// Dismiss banner
|
||||
function dismissBanner() {
|
||||
localStorage.setItem('pwa-banner-dismissed', Date.now().toString());
|
||||
const banner = document.getElementById('pwa-install-banner');
|
||||
if (banner) {
|
||||
banner.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
banner.style.display = 'none';
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize UI components and listeners
|
||||
function initPwaUI() {
|
||||
// If already in standalone mode, hide all promotional components
|
||||
if (isStandalone) {
|
||||
console.log('[PWA] Applicazione avviata in modalità Standalone. Nascondo elementi PWA.');
|
||||
return;
|
||||
}
|
||||
|
||||
const headerBtn = document.getElementById('pwa-header-install-btn');
|
||||
const desktopBtn = document.getElementById('desktopPwaInstallBtn');
|
||||
const banner = document.getElementById('pwa-install-banner');
|
||||
const bannerInstallBtn = document.getElementById('pwa-banner-install-btn');
|
||||
const bannerCloseBtn = document.getElementById('pwa-banner-close-btn');
|
||||
|
||||
// On iOS, show the installation buttons immediately (as they don't support beforeinstallprompt)
|
||||
if (isIOS) {
|
||||
console.log('[PWA] Rilevato dispositivo iOS');
|
||||
if (headerBtn) headerBtn.style.display = 'inline-flex';
|
||||
if (desktopBtn) desktopBtn.style.display = 'inline-flex';
|
||||
|
||||
if (banner && !isBannerDismissed()) {
|
||||
banner.style.display = 'flex';
|
||||
setTimeout(() => banner.classList.add('show'), 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Attach click listeners to all PWA installation buttons
|
||||
const triggerInstall = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (window.deferredPrompt) {
|
||||
// Show native install prompt (Android / Desktop Chrome / Edge)
|
||||
window.deferredPrompt.prompt();
|
||||
window.deferredPrompt.userChoice.then((choiceResult) => {
|
||||
if (choiceResult.outcome === 'accepted') {
|
||||
console.log('[PWA] Utente ha installato la PWA');
|
||||
dismissBanner();
|
||||
} else {
|
||||
console.log('[PWA] Utente ha annullato l\'installazione');
|
||||
}
|
||||
window.deferredPrompt = null;
|
||||
});
|
||||
} else {
|
||||
// Fallback for iOS Safari or other unsupported prompts
|
||||
showInstructionsModal();
|
||||
}
|
||||
};
|
||||
|
||||
if (headerBtn) headerBtn.addEventListener('click', triggerInstall);
|
||||
if (desktopBtn) desktopBtn.addEventListener('click', triggerInstall);
|
||||
if (bannerInstallBtn) bannerInstallBtn.addEventListener('click', triggerInstall);
|
||||
|
||||
if (bannerCloseBtn) {
|
||||
bannerCloseBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
dismissBanner();
|
||||
});
|
||||
}
|
||||
|
||||
// Modal Close logic
|
||||
const modal = document.getElementById('pwa-instructions-modal');
|
||||
const modalCloseBtnTop = document.getElementById('pwa-modal-close-btn');
|
||||
|
||||
const closeModal = () => {
|
||||
if (modal) {
|
||||
modal.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
modal.style.display = 'none';
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
if (modalCloseBtnTop) modalCloseBtnTop.addEventListener('click', closeModal);
|
||||
if (modal) {
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) closeModal();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for beforeinstallprompt (Chrome / Android / Edge)
|
||||
window.addEventListener('beforeinstallprompt', (e) => {
|
||||
// Prevent Chrome 67 and earlier from automatically showing the prompt
|
||||
e.preventDefault();
|
||||
|
||||
// Se siamo su desktop, non salviamo il prompt e non mostriamo nessun banner promozionale PWA
|
||||
if (!isMobile) {
|
||||
console.log('[PWA] Installazione via browser intercettata su desktop. Ignorata per requisiti.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Stash the event so it can be triggered later.
|
||||
window.deferredPrompt = e;
|
||||
|
||||
console.log('[PWA] Evento beforeinstallprompt intercettato.');
|
||||
|
||||
// Show custom buttons and banner (if not dismissed)
|
||||
const headerBtn = document.getElementById('pwa-header-install-btn');
|
||||
const desktopBtn = document.getElementById('desktopPwaInstallBtn');
|
||||
const banner = document.getElementById('pwa-install-banner');
|
||||
|
||||
if (headerBtn) headerBtn.style.display = 'inline-flex';
|
||||
if (desktopBtn) desktopBtn.style.display = 'inline-flex';
|
||||
|
||||
if (banner && !isBannerDismissed()) {
|
||||
banner.style.display = 'flex';
|
||||
setTimeout(() => banner.classList.add('show'), 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Track successful installation
|
||||
window.addEventListener('appinstalled', () => {
|
||||
console.log('[PWA] L\'applicazione è stata installata con successo.');
|
||||
window.deferredPrompt = null;
|
||||
|
||||
// Hide all promotional components
|
||||
const headerBtn = document.getElementById('pwa-header-install-btn');
|
||||
const desktopBtn = document.getElementById('desktopPwaInstallBtn');
|
||||
const banner = document.getElementById('pwa-install-banner');
|
||||
|
||||
if (headerBtn) headerBtn.style.display = 'none';
|
||||
if (desktopBtn) desktopBtn.style.display = 'none';
|
||||
if (banner) banner.style.display = 'none';
|
||||
});
|
||||
|
||||
// Show instructions modal (iOS / Fallback)
|
||||
function showInstructionsModal() {
|
||||
const modal = document.getElementById('pwa-instructions-modal');
|
||||
const content = document.getElementById('pwa-instructions-content');
|
||||
if (!modal || !content) return;
|
||||
|
||||
if (isIOS) {
|
||||
content.innerHTML = `
|
||||
<div class="pwa-step">
|
||||
<div class="pwa-step-num">1</div>
|
||||
<div class="pwa-step-text">Tocca l'icona di <strong>Condividi</strong> <span class="pwa-inline-icon"><i class="material-icons" style="font-size:18px; color:#f7b835;">share</i></span> (il quadrato con la freccia verso l'alto) nella barra in basso di Safari.</div>
|
||||
</div>
|
||||
<div class="pwa-step">
|
||||
<div class="pwa-step-num">2</div>
|
||||
<div class="pwa-step-text">Scorri l'elenco delle opzioni verso il basso e seleziona <strong>Aggiungi alla schermata Home</strong> <span class="pwa-inline-icon"><i class="material-icons" style="font-size:18px; color:#f7b835;">add_box</i></span>.</div>
|
||||
</div>
|
||||
<div class="pwa-step">
|
||||
<div class="pwa-step-num">3</div>
|
||||
<div class="pwa-step-text">Tocca <strong>Aggiungi</strong> nell'angolo in alto a destra per inserire l'icona sul tuo telefono.</div>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
content.innerHTML = `
|
||||
<div class="pwa-step">
|
||||
<div class="pwa-step-num">1</div>
|
||||
<div class="pwa-step-text">Apri il menu delle impostazioni del browser toccando i <strong>tre puntini</strong> <span class="pwa-inline-icon"><i class="material-icons" style="font-size:18px; color:#f7b835;">more_vert</i></span> in alto a destra.</div>
|
||||
</div>
|
||||
<div class="pwa-step">
|
||||
<div class="pwa-step-num">2</div>
|
||||
<div class="pwa-step-text">Seleziona la voce <strong>Installa applicazione</strong> o <strong>Aggiungi a schermata Home</strong>.</div>
|
||||
</div>
|
||||
<div class="pwa-step">
|
||||
<div class="pwa-step-num">3</div>
|
||||
<div class="pwa-step-text">Conferma per scaricare la PWA sul tuo telefono.</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
modal.style.display = 'flex';
|
||||
setTimeout(() => modal.classList.add('show'), 10);
|
||||
}
|
||||
|
||||
// Run on DOM loaded
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initPwaUI);
|
||||
} else {
|
||||
initPwaUI();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user