diff --git a/src/components/update-notification.js b/src/components/update-notification.js index af5532e..7df6e44 100644 --- a/src/components/update-notification.js +++ b/src/components/update-notification.js @@ -35,7 +35,7 @@ export class UpdateNotification { if (getUpdateManager()) { console.log('✅ [UpdateNotification] UpdateManager trovato, bind eventi notifica'); this.bindEvents(); - + // RIMOSSO: Il controllo dello stato iniziale può causare problemi // L'updateManager dovrebbe emettere gli eventi corretti al momento giusto } else { @@ -357,10 +357,23 @@ export class UpdateNotification { */ bindButtonEvents() { const buttons = this.container.querySelectorAll('[data-action]'); + console.log('🔔 [UpdateNotification] Trovati', buttons.length, 'pulsanti con data-action'); buttons.forEach(button => { + console.log('🔔 [UpdateNotification] Binding evento per pulsante:', button.dataset.action); button.addEventListener('click', (e) => { - const action = e.target.dataset.action; - this.handleAction(action); + // Trova il pulsante con data-action, anche se si clicca su un elemento figlio (come l'icona SVG) + let target = e.target; + while (target && !target.dataset.action) { + target = target.parentElement; + } + + const action = target ? target.dataset.action : null; + console.log('🔔 [UpdateNotification] Target trovato:', target, 'Action:', action); + if (action) { + this.handleAction(action); + } else { + console.warn('🔔 [UpdateNotification] Nessuna azione trovata per questo click'); + } }); }); } @@ -369,6 +382,7 @@ export class UpdateNotification { * Handles button actions */ handleAction(action) { + console.log('🔔 [UpdateNotification] Azione pulsante:', action); switch (action) { case 'download': this.startDownload(); @@ -538,14 +552,15 @@ export class UpdateNotification { } // Verifica se siamo in modalità sviluppo senza test mode - const updateManager = getUpdateManager(); - if (updateManager && updateManager.isDevelopmentMode && updateManager.isDevelopmentMode()) { - const hasTestMode = localStorage.getItem('presto_force_update_test') === 'true'; - if (!hasTestMode) { - console.log('🔍 [UpdateNotification] Modalità sviluppo senza test mode - non mostro notifica'); - return; - } - } + // RIMOSSO: Ora permettiamo la notifica anche in modalità sviluppo per GitHub releases + // const updateManager = getUpdateManager(); + // if (updateManager && updateManager.isDevelopmentMode && updateManager.isDevelopmentMode()) { + // const hasTestMode = localStorage.getItem('presto_force_update_test') === 'true'; + // if (!hasTestMode) { + // console.log('🔍 [UpdateNotification] Modalità sviluppo senza test mode - non mostro notifica'); + // return; + // } + // } // Don't show if this version has been skipped if (this.isVersionSkipped(updateInfo.version)) { @@ -659,5 +674,5 @@ export class UpdateNotification { } } -// Export singleton instance -export const updateNotification = new UpdateNotification(); +// Export the class, not an instance - let main.js handle initialization +// export const updateNotification = new UpdateNotification(); diff --git a/src/main.js b/src/main.js index 2a22798..4e8d477 100644 --- a/src/main.js +++ b/src/main.js @@ -6,7 +6,7 @@ import { TeamManager } from './managers/team-manager.js'; // Auth manager will be imported after Supabase is loaded import { PomodoroTimer } from './core/pomodoro-timer.js'; import { NotificationUtils } from './utils/common-utils.js'; -// Removed unused import: updateNotification +import { UpdateNotification } from './components/update-notification.js'; // Global application state let timer = null; @@ -299,31 +299,31 @@ async function initializeEarlyTheme() { // Helper function to check if Tauri is available and ready function isTauriReady() { - return typeof window !== 'undefined' && - window.__TAURI__ && - window.__TAURI__.core && - typeof window.__TAURI__.core.invoke === 'function'; + return typeof window !== 'undefined' && + window.__TAURI__ && + window.__TAURI__.core && + typeof window.__TAURI__.core.invoke === 'function'; } // Helper function to wait for Tauri to be ready (with timeout) function waitForTauri(maxWaitTime = 2000) { return new Promise((resolve) => { const startTime = Date.now(); - + const checkTauri = () => { if (isTauriReady()) { resolve(true); return; } - + if (Date.now() - startTime > maxWaitTime) { resolve(false); return; } - + setTimeout(checkTauri, 50); }; - + checkTauri(); }); } @@ -331,10 +331,10 @@ async function initializeEarlyTheme() { try { // Wait for Tauri to be ready before trying to load settings const tauriReady = await waitForTauri(); - + if (tauriReady) { console.log('🎨 Tauri is ready, loading theme from settings...'); - + try { const { invoke } = window.__TAURI__.core; const savedSettings = await invoke('load_settings'); @@ -1467,19 +1467,19 @@ async function initializeApplication() { console.log('🚀 Application already fully initialized, skipping...'); return; } - + // Prevent concurrent initialization attempts if (window._appInitializing) { console.log('🚀 Application initialization already in progress, skipping...'); return; } - + // Set initialization flag early to prevent race conditions window._appInitializing = true; - + try { console.log('🚀 Initializing Presto application...'); - + // Show loading state const loadingOverlay = document.createElement('div'); loadingOverlay.id = 'app-loading'; @@ -1512,7 +1512,7 @@ async function initializeApplication() { if (stuckOverlay) { console.error('⚠️ Initialization timeout - removing loading overlay'); stuckOverlay.remove(); - + // Show error message NotificationUtils.showNotificationPing('Initialization timed out. Please refresh! 🔄', 'error'); } @@ -1556,6 +1556,11 @@ async function initializeApplication() { window.updateManager.loadPreferences(); // Carica le preferenze salvate se supportato } + // Initialize Update Notification component + console.log('🔔 Initializing Update Notification...'); + const updateNotification = new UpdateNotification(); + window.updateNotification = updateNotification; // Make it globally available + // Skip first run authentication - proceed directly with guest mode if (authManager.isFirstRun()) { console.log('👋 First run detected, proceeding as guest...'); @@ -1613,7 +1618,7 @@ async function initializeApplication() { // Clear safety timeout clearTimeout(safetyTimeout); - + // Mark as fully initialized window._appFullyInitialized = true; window._appInitializing = false; @@ -1629,21 +1634,21 @@ async function initializeApplication() { } catch (error) { console.error('❌ Failed to initialize application:', error); - + // Clear safety timeout and remove loading overlay even on error clearTimeout(safetyTimeout); const loadingOverlayError = document.getElementById('app-loading'); if (loadingOverlayError) { loadingOverlayError.remove(); } - + // Show error notification NotificationUtils.showNotificationPing('Failed to initialize app. Please refresh! 🔄', 'error'); - + // Reset initialization flags on error so user can retry window._appInitializing = false; window._appFullyInitialized = false; - + // Show error screen instead of leaving user with blank screen const errorScreen = document.createElement('div'); errorScreen.id = 'app-error'; @@ -1891,9 +1896,10 @@ function setupUpdateManagement() { } }); - updateManager.on('checkError', () => { + updateManager.on('checkError', (event) => { if (updateStatus) { - updateStatus.innerHTML = 'Check failed'; + const errorMessage = event?.detail?.message || 'Check failed'; + updateStatus.innerHTML = `${errorMessage}`; } }); diff --git a/src/managers/update-manager-global.js b/src/managers/update-manager-global.js index 632fe7a..6f7ed58 100644 --- a/src/managers/update-manager-global.js +++ b/src/managers/update-manager-global.js @@ -19,10 +19,8 @@ window.UpdateManagerV2 = class UpdateManagerV2 { // Eventi personalizzati this.eventTarget = new EventTarget(); - // Inizializza il controllo automatico solo se non siamo in dev mode - if (!this.isDevelopmentMode()) { - this.startAutoCheck(); - } + // Inizializza il controllo automatico sempre (ora funziona anche in dev mode) + this.startAutoCheck(); console.log('✅ UpdateManager v2 inizializzato (global)'); } @@ -99,15 +97,15 @@ window.UpdateManagerV2 = class UpdateManagerV2 { if (window.__TAURI__?.app?.getVersion) { return await window.__TAURI__.app.getVersion(); } - + if (window.__TAURI__?.core?.invoke) { return await window.__TAURI__.core.invoke('plugin:app|version'); } throw new Error('API versione non disponibile'); } catch (error) { - console.warn('❌ Errore recupero versione:', error); - return '0.2.2'; // fallback + console.error('❌ Impossibile ottenere la versione dell\'app:', error); + throw new Error('Impossibile determinare la versione corrente dell\'applicazione'); } } @@ -142,7 +140,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { enableTestMode() { localStorage.setItem('presto_force_update_test', 'true'); console.warn('⚠️ MODALITÀ TEST AGGIORNAMENTI ATTIVATA'); - + if (!this.isDevelopmentMode() && this.autoCheck && !this.checkInterval) { this.startAutoCheck(); } @@ -156,7 +154,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { disableTestMode() { localStorage.removeItem('presto_force_update_test'); console.log('ℹ️ Modalità test aggiornamenti disattivata'); - + if (this.isDevelopmentMode()) { this.stopAutoCheck(); } @@ -245,16 +243,18 @@ window.UpdateManagerV2 = class UpdateManagerV2 { * Avvia il controllo automatico degli aggiornamenti */ startAutoCheck() { - if (this.autoCheck && !this.checkInterval && !this.isDevelopmentMode()) { + if (this.autoCheck && !this.checkInterval) { // Controlla ogni ora this.checkInterval = setInterval(() => { + console.log('🔄 Controllo automatico periodico degli aggiornamenti...'); this.checkForUpdates(false); // silent check }, 60 * 60 * 1000); - // Controllo iniziale dopo 30 secondi + // Controllo iniziale dopo 5 secondi setTimeout(() => { - this.checkForUpdates(false); - }, 30000); + console.log('🔄 Controllo automatico iniziale degli aggiornamenti...'); + this.checkForUpdates(false); // silent - mostra il banner se c'è un aggiornamento + }, 5000); console.log('🔄 Controllo automatico aggiornamenti avviato'); } @@ -277,7 +277,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { compareVersions(a, b) { const cleanA = a.replace(/^v/, ''); const cleanB = b.replace(/^v/, ''); - + const aParts = cleanA.split('.').map(n => parseInt(n) || 0); const bParts = cleanB.split('.').map(n => parseInt(n) || 0); @@ -292,6 +292,83 @@ window.UpdateManagerV2 = class UpdateManagerV2 { return 0; } + /** + * Controlla solo la versione da GitHub senza tentare l'installazione (per modalità sviluppo) + */ + async checkVersionFromGitHub(showDialog = true) { + try { + // Ottieni versione corrente + let currentVersion; + try { + currentVersion = await this.getAppVersion(); + console.log(`📋 Versione corrente: ${currentVersion}`); + } catch (error) { + console.error('❌ Errore nel recupero della versione corrente:', error); + this.emit('checkError', { error: 'Impossibile determinare la versione corrente' }); + if (showDialog) { + alert('Impossibile verificare gli aggiornamenti: versione corrente non determinabile'); + } + return false; + } + + // Controlla ultima release su GitHub + const response = await fetch('https://api.github.com/repos/murdercode/presto/releases/latest'); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + + const githubRelease = await response.json(); + const latestVersion = githubRelease.tag_name.replace(/^v/, ''); + + console.log(`📋 Ultima versione GitHub: ${latestVersion}`); + + // Confronta versioni + if (this.compareVersions(latestVersion, currentVersion) <= 0) { + console.log('✅ Nessun aggiornamento disponibile'); + this.updateAvailable = false; + this.currentUpdate = null; + this.emit('updateNotAvailable'); + + if (showDialog) { + alert(`Nessun aggiornamento disponibile.\n\nVersione corrente: ${currentVersion}\nUltima versione: ${latestVersion}`); + } + return false; + } + + // Aggiornamento disponibile + console.log(`🎉 Aggiornamento disponibile: ${latestVersion}`); + this.updateAvailable = true; + this.currentUpdate = { + version: latestVersion, + body: githubRelease.body || '', + date: githubRelease.published_at + }; + + // console.log('📢 Emetto evento updateAvailable con:', this.currentUpdate); // Debug rimosso + this.emit('updateAvailable', this.currentUpdate); + + if (showDialog) { + const message = `🎉 Aggiornamento disponibile!\n\n` + + `Versione corrente: ${currentVersion}\n` + + `Nuova versione: ${latestVersion}\n\n` + + `Nota: In modalità sviluppo, scarica manualmente da GitHub.`; + alert(message); + } + + return true; + + } catch (error) { + console.error('❌ Errore controllo versione GitHub:', error); + this.emit('checkError', { error: `Errore di rete: ${error.message}` }); + if (showDialog) { + alert(`Errore nel controllo degli aggiornamenti:\n${error.message}`); + } + return false; + } finally { + this.isChecking = false; + } + } + /** * Controlla se sono disponibili aggiornamenti usando approccio ibrido sicuro */ @@ -312,12 +389,9 @@ window.UpdateManagerV2 = class UpdateManagerV2 { const hasTestMode = localStorage.getItem('presto_force_update_test') === 'true'; if (isDevMode && !hasTestMode) { - console.warn('⚠️ Modalità sviluppo - controllo disabilitato'); - this.emit('updateNotAvailable'); - if (showDialog) { - await this.showDevelopmentMessage(); - } - return false; + console.log('🔍 Modalità sviluppo - controllo tramite GitHub API senza installazione'); + // In modalità sviluppo facciamo solo il controllo della versione senza installazione + return await this.checkVersionFromGitHub(showDialog); } // Se è modalità test, simula un aggiornamento @@ -329,8 +403,21 @@ window.UpdateManagerV2 = class UpdateManagerV2 { // Controlla aggiornamenti reali // 1. Prima prova con l'API GitHub per avere info complete - const currentVersion = await this.getAppVersion(); - console.log(`📋 Versione corrente: ${currentVersion}`); + let currentVersion; + try { + currentVersion = await this.getAppVersion(); + console.log(`📋 Versione corrente: ${currentVersion}`); + } catch (versionError) { + console.error('❌ Impossibile ottenere la versione corrente:', versionError.message); + this.updateAvailable = false; + this.currentUpdate = null; + if (!silent) { + this.eventTarget.dispatchEvent(new CustomEvent('checkError', { + detail: { message: 'Impossibile verificare la versione corrente dell\'applicazione' } + })); + } + return false; + } // Controlla GitHub API const response = await fetch('https://api.github.com/repos/StefanoNovelli/presto/releases/latest'); @@ -360,7 +447,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { if (tauriAPI) { console.log('🔄 Usando API Tauri updater...'); const tauriUpdate = await tauriAPI.check(); - + if (tauriUpdate && tauriUpdate.available) { console.log('✅ Aggiornamento confermato via Tauri API'); this.updateAvailable = true; @@ -417,10 +504,10 @@ window.UpdateManagerV2 = class UpdateManagerV2 { */ async simulateUpdate() { console.log('🧪 Simulazione aggiornamento per test...'); - + const currentVersion = await this.getAppVersion(); const simulatedNewVersion = this.incrementVersion(currentVersion); - + const update = { version: simulatedNewVersion, date: new Date().toISOString(), @@ -490,16 +577,16 @@ window.UpdateManagerV2 = class UpdateManagerV2 { // Se supporta download automatico via Tauri if (this.currentUpdate.isAutoDownloadable && this.currentUpdate.source === 'tauri-api') { console.log('📥 Download automatico via Tauri...'); - + const tauriAPI = await this.getTauriUpdaterAPI(); if (tauriAPI && tauriAPI.downloadAndInstall) { await tauriAPI.downloadAndInstall((progress) => { console.log(`📥 Progresso download: ${progress}%`); this.downloadProgress = progress; - this.emit('downloadProgress', { + this.emit('downloadProgress', { progress, chunkLength: progress, - contentLength: 100 + contentLength: 100 }); }); @@ -511,10 +598,10 @@ window.UpdateManagerV2 = class UpdateManagerV2 { }); this.emit('downloadFinished'); - + // Installa e riavvia this.emit('installFinished'); - + const shouldRestart = await this.askConfirmation( 'Aggiornamento scaricato e installato con successo!\n\nVuoi riavviare ora l\'applicazione?', { title: 'Aggiornamento Completato' } @@ -528,7 +615,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { // Download manuale console.log('🌐 Reindirizzamento a download manuale...'); await this.openDownloadUrl(this.currentUpdate.downloadUrl); - + this.emit('downloadError', new Error('Download manuale richiesto')); } @@ -546,15 +633,15 @@ window.UpdateManagerV2 = class UpdateManagerV2 { */ async simulateDownloadAndInstall() { console.log('🧪 Simulazione download...'); - + // Simula progresso download for (let i = 0; i <= 100; i += 10) { await new Promise(resolve => setTimeout(resolve, 100)); this.downloadProgress = i; - this.emit('downloadProgress', { + this.emit('downloadProgress', { progress: i, chunkLength: i, - contentLength: 100 + contentLength: 100 }); } @@ -584,7 +671,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { */ setAutoCheck(enabled) { this.autoCheck = enabled; - + if (enabled) { this.startAutoCheck(); } else { @@ -623,6 +710,7 @@ window.UpdateManagerV2 = class UpdateManagerV2 { } emit(event, data = null) { + // console.log(`📢 [UpdateManager] Emetto evento: ${event}`, data); // Debug rimosso this.eventTarget.dispatchEvent(new CustomEvent(event, { detail: data })); } diff --git a/src/utils/theme-loader.js b/src/utils/theme-loader.js index b121c03..a2f9c22 100644 --- a/src/utils/theme-loader.js +++ b/src/utils/theme-loader.js @@ -39,7 +39,7 @@ class ThemeLoader { // that gets updated by the build process or manually maintained // This could be enhanced to use a build-time script that generates this list - const knownThemes = [ + const knownThemes = [ 'espresso.css', 'pipboy.css', 'pommodore64.css'