From 4dae2727066d88bf5025eb1118d1a1bc4c3a2ff5 Mon Sep 17 00:00:00 2001 From: mickael pol Date: Wed, 25 Mar 2026 23:12:27 +0100 Subject: [PATCH] v1.1.4 - correctif de bug mineur + features. --- README.md | 12 +++++++ main.js | 18 ++++++++-- package.json | 2 +- preload.js | 1 + src/index.html | 93 +++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 103 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8cbe006..9e09a9f 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,18 @@ dd-timer/ ## Changelog +### v1.1.4 +- ✨ **Reinitialisation des statistiques** — bouton dans l'onglet Statistiques pour remettre a zero tous les bebes, historiques et stats archivees (avec confirmation) +- 🔧 Correction "vider l'enclos" / "nouvelle fournee" / "supprimer enclos" — remplacement de confirm() par un dialogue natif Electron pour corriger le bug qui rendait tous les inputs inutilisables +- 🔧 Correction du bouton "Quitter" — utilisation de process.exit() pour forcer l'arret complet du processus + +### v1.1.3 +- ✨ **Inputs intelligents** — les champs numeriques se vident au clic pour saisir facilement, et restaurent la valeur precedente si rien n'est change +- 🔧 Correction du bug "enclos vide" — apres avoir vide un enclos ou lance une nouvelle fournee, une dragodinde est automatiquement ajoutee et les inputs restent editables +- 🔧 Correction "nouvelle fournee" — ne vide plus l'historique de session des bebes, seul "vider l'enclos" le fait +- 🔧 Correction des statistiques globales — supprimer un enclos conserve desormais ses stats dans les statistiques globales (archivage automatique) +- 🔧 Correction du bouton "Quitter" — la fermeture complete de l'app fonctionne maintenant correctement + ### v1.1.2 - 💾 **Sauvegarde persistante** — les donnees sont maintenant sauvegardees dans un fichier JSON, plus de perte de statistiques apres une mise a jour - ❌ **Dialogue de fermeture** — cliquer sur la croix propose de minimiser en arriere-plan ou de quitter completement diff --git a/main.js b/main.js index 1567983..f02833b 100644 --- a/main.js +++ b/main.js @@ -65,8 +65,8 @@ function createWindow() { detail: 'Minimiser garde l\'app en arriere-plan.\nLes alarmes continueront de sonner.', }); if (choice === 1) { - isQuitting = true; - app.quit(); + if (tray) { tray.destroy(); tray = null; } + process.exit(0); } else { mainWindow.hide(); } @@ -142,6 +142,20 @@ ipcMain.on('show-notification', (event, { title, body }) => { fireNotification(title, body); }); +// Dialogue de confirmation natif (remplace confirm() du renderer qui casse les inputs) +ipcMain.handle('show-confirm', (event, { title, message, detail }) => { + const choice = dialog.showMessageBoxSync(mainWindow, { + type: 'question', + buttons: ['Annuler', 'Confirmer'], + defaultId: 0, + cancelId: 0, + title: title || 'Confirmation', + message: message || '', + detail: detail || '', + }); + return choice === 1; +}); + // ─── SAUVEGARDE FICHIER (persistante entre mises à jour) ───────────────── const dataFile = path.join(app.getPath('userData'), 'dd-timer-data.json'); diff --git a/package.json b/package.json index 75ec18f..0d71465 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minuteur-dragodinde", - "version": "1.1.2", + "version": "1.1.4", "description": "Minuteur elevage Dragodinde Dofus 3", "main": "main.js", "author": "Mickael", diff --git a/preload.js b/preload.js index 6549239..73636ad 100644 --- a/preload.js +++ b/preload.js @@ -12,6 +12,7 @@ contextBridge.exposeInMainWorld('electronAPI', { showNotification: (title, body) => ipcRenderer.send('show-notification', { title, body }), sendNtfy: (url, title, message) => ipcRenderer.send('send-ntfy', { url, title, message }), focusWindow: () => ipcRenderer.send('focus-window'), + showConfirm: (title, message, detail) => ipcRenderer.invoke('show-confirm', { title, message, detail }), onPlayAlarmSound: (cb) => ipcRenderer.on('play-alarm-sound', () => cb()), // Version diff --git a/src/index.html b/src/index.html index a172bfe..e783e4f 100644 --- a/src/index.html +++ b/src/index.html @@ -569,7 +569,7 @@ const RACES_DATA={ }; -let S={enclos:[],activeId:null,nextEnclosId:1,alarmSound:'arpege',notifsEnabled:true,ntfyTopic:''}; +let S={enclos:[],activeId:null,nextEnclosId:1,alarmSound:'arpege',notifsEnabled:true,ntfyTopic:'',archivedStats:[]}; const NTFY_BASE='https://ntfy.mickael-pol.fr'; const NTFY_REDIRECT='https://ntfy-redirect.mickael-pol.fr'; const lastTickIdx={}; @@ -856,11 +856,22 @@ function addEnclos(){ S.enclos.push(e);S.activeId=e.id; save();render();addDD(e.id); } -function removeEnclos(id){ +async function removeEnclos(id){ if(S.enclos.length<=1)return; + const enc=S.enclos.find(e=>e.id===id); + if(!enc)return; + const ok=await window.electronAPI.showConfirm('Supprimer l\'enclos',`Supprimer "${enc.name}" ?`,'Les statistiques globales seront conservees.'); + if(!ok)return; + // Archiver les stats (babyHistory) pour les conserver dans les statistiques globales + const hist=enc.babyHistory||enc.babies||[]; + if(hist.length){ + if(!S.archivedStats)S.archivedStats=[]; + S.archivedStats.push(...hist.map(b=>({...b,fromEnclos:enc.name}))); + } S.enclos=S.enclos.filter(e=>e.id!==id); if(S.activeId===id||S.activeId==='dashboard')S.activeId=S.enclos[0].id; - save();render(); + save(); + render(); } function selectEnclos(id){S.activeId=id;save();renderTabs();renderContent();} @@ -915,20 +926,23 @@ function removeDD(encId,ddId){ enc.dragodindes=enc.dragodindes.filter(d=>d.id!==ddId); save();renderDDs(enc); } -function viderEnclos(encId){ +async function viderEnclos(encId){ const enc=S.enclos.find(e=>e.id===encId); if(!enc)return; - if(!confirm(`Vider "${enc.name}" ?\n\nToutes les dragodindes seront supprimées.\nLes bébés et statistiques sont conservés.`))return; + const ok=await window.electronAPI.showConfirm('Vider l\'enclos',`Vider "${enc.name}" ?`,'Toutes les dragodindes seront supprimees.\nLes bebes et statistiques sont conserves.'); + if(!ok)return; enc.dragodindes=[]; enc.nextDdId=1; enc.timer={running:false,startTime:null,pausedAt:null,pausedMs:0,snapGauges:{},snapStats:{}}; enc.alerted={}; enc.activeGauges=[]; Object.keys(enc.gaugeLevels).forEach(k=>{enc.gaugeLevels[k]=0;}); - // babies session vide mais babyHistory intact enc.babies=[]; - lockInputs(encId,false); - save();renderContent(); + // Ajouter une DD par défaut + const newId=enc.nextDdId++; + enc.dragodindes.push({id:newId,name:`Dragodinde ${newId}`,stats:{serenite:0,endurance:0,maturite:0,amour:0,xp:1},targets:{...DEFAULT_TARGETS}}); + save(); + render(); } function updateName(encId,ddId,v){ const enc=S.enclos.find(e=>e.id===encId); @@ -956,18 +970,22 @@ function updateStatDirect(encId,ddId,stat,v){ save();updateLive(); } -function nouvelleFournee(encId){ +async function nouvelleFournee(encId){ const enc=S.enclos.find(e=>e.id===encId); if(!enc)return; - if(!confirm(`Nouvelle fournée pour ${enc.name} ?\n\nLes dragodindes actuelles seront supprimées.\nLes bébés et l'historique sont conservés.`))return; + const ok=await window.electronAPI.showConfirm('Nouvelle fournee',`Nouvelle fournee pour ${enc.name} ?`,'Les dragodindes actuelles seront supprimees.\nLes bebes et l\'historique sont conserves.'); + if(!ok)return; enc.dragodindes=[]; enc.nextDdId=1; enc.timer={running:false,startTime:null,pausedAt:null,pausedMs:0,snapGauges:{},snapStats:{}}; enc.alerted={}; enc.activeGauges=[]; Object.keys(enc.gaugeLevels).forEach(k=>{enc.gaugeLevels[k]=0;}); - enc.babies=[]; - save();renderContent(); + // Ajouter une DD par défaut + const newId=enc.nextDdId++; + enc.dragodindes.push({id:newId,name:`Dragodinde ${newId}`,stats:{serenite:0,endurance:0,maturite:0,amour:0,xp:1},targets:{...DEFAULT_TARGETS}}); + save(); + render(); } function updateStat(encId,ddId,gid,v){ const enc=S.enclos.find(e=>e.id===encId); @@ -1070,6 +1088,7 @@ async function load(){ S.alarmSound=d.alarmSound||'arpege'; S.notifsEnabled=d.notifsEnabled!==undefined?d.notifsEnabled:true; S.ntfyTopic=d.ntfyTopic||''; + S.archivedStats=d.archivedStats||[]; // Migration: ancien format ntfyUrl → ntfyTopic if(!S.ntfyTopic&&d.ntfyUrl){const m=d.ntfyUrl.match(/\/([^\/]+)$/);if(m)S.ntfyTopic=m[1];} S.enclos.forEach(enc=>{ @@ -1315,6 +1334,8 @@ function renderGaugesCfg(enc){ / 100 000 @@ -1390,6 +1411,8 @@ function renderDDs(enc){ `; }); @@ -1987,17 +2010,41 @@ function changeCount(delta){ // ══════════════════════════════════════════ // STATS TAB // ══════════════════════════════════════════ +async function resetStats(){ + const ok=await window.electronAPI.showConfirm( + 'Reinitialiser les statistiques', + 'Reinitialiser toutes les statistiques ?', + 'Cette action est irreversible.\nTous les bebes enregistres, l\'historique de chaque enclos et les statistiques archivees seront definitivement supprimes.' + ); + if(!ok)return; + S.archivedStats=[]; + S.enclos.forEach(enc=>{ + enc.babies=[]; + enc.babyHistory=[]; + }); + save(); + render(); +} function renderStats(){ const c=document.getElementById('enclos-content'); c.removeAttribute('data-enc'); - // Agréger toutes les données + // Agréger toutes les données (enclos actifs + stats archivées des enclos supprimés) let totalDD=0,totalBabies=0,totalSessions=0; const raceMap={}; const enclosStats=[]; + // Stats archivées (enclos supprimés) + const archived=S.archivedStats||[]; + archived.forEach(b=>{ + if(!raceMap[b.race])raceMap[b.race]={count:0,gen:b.gen}; + raceMap[b.race].count+=b.count; + totalBabies+=b.count; + }); + const archivedMax=archived.reduce((s,b)=>s+Math.min(5,Math.floor((b.ddCount||1)/2)),0); + S.enclos.forEach(enc=>{ - const babies=(enc.babyHistory||enc.babies||[]); // utilise l'historique permanent + const babies=(enc.babyHistory||enc.babies||[]); const nbBabies=babies.reduce((s,b)=>s+b.count,0); const nbDD=enc.dragodindes.length; totalDD+=nbDD; @@ -2011,8 +2058,6 @@ function renderStats(){ }); if(nbBabies>0){ - // Calcul taux de réussite basé sur le ddCount stocké lors de l'ajout - // → résiste à la suppression/nouvelle fournée de DD const maxPossible=babies.reduce((s,b)=>{ const m=Math.min(5,Math.floor((b.ddCount||1)/2)); return s+m; @@ -2022,8 +2067,8 @@ function renderStats(){ } }); - // Taux global basé sur les ddCount stockés - const totalMax=S.enclos.reduce((s,e)=>{ + // Taux global (enclos actifs + archivés) + const totalMax=archivedMax+S.enclos.reduce((s,e)=>{ const hist=(e.babyHistory||e.babies||[]); return s+hist.reduce((ss,b)=>ss+Math.min(5,Math.floor((b.ddCount||1)/2)),0); },0); @@ -2034,8 +2079,16 @@ function renderStats(){ const maxRaceCount=racesSorted[0]?.[1].count||1; c.innerHTML=` -
- Statistiques globales +
+
+ Statistiques globales +
+