v1.1.2 - correctifs mineur, sauvegarde persistante, dialogue de fermeture.

This commit is contained in:
mickael pol 2026-03-25 19:44:07 +01:00
parent 5af7350d0b
commit 2f4fe578ab
5 changed files with 57 additions and 16 deletions

View File

@ -70,6 +70,10 @@ dd-timer/
## Changelog ## Changelog
### 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
### v1.1.1 ### v1.1.1
- 🔧 Correction de la mise a jour automatique — l'app se relance maintenant toute seule apres installation - 🔧 Correction de la mise a jour automatique — l'app se relance maintenant toute seule apres installation
- 🔧 Correction de l'affichage du titre des notifications ntfy (encodage base64 supprime) - 🔧 Correction de l'affichage du titre des notifications ntfy (encodage base64 supprime)

37
main.js
View File

@ -55,12 +55,21 @@ function createWindow() {
mainWindow.on('close', (e) => { mainWindow.on('close', (e) => {
if (!isQuitting) { if (!isQuitting) {
e.preventDefault(); e.preventDefault();
mainWindow.hide(); const choice = dialog.showMessageBoxSync(mainWindow, {
if (tray) tray.displayBalloon({ type: 'question',
iconType: 'info', buttons: ['Minimiser', 'Quitter'],
defaultId: 0,
cancelId: 0,
title: 'Minuteur Dragodinde', title: 'Minuteur Dragodinde',
content: "Tourne en arriere-plan. Les alarmes sonneront normalement.", message: 'Que souhaites-tu faire ?',
detail: 'Minimiser garde l\'app en arriere-plan.\nLes alarmes continueront de sonner.',
}); });
if (choice === 1) {
isQuitting = true;
app.quit();
} else {
mainWindow.hide();
}
} }
}); });
@ -133,6 +142,22 @@ ipcMain.on('show-notification', (event, { title, body }) => {
fireNotification(title, body); fireNotification(title, body);
}); });
// ─── SAUVEGARDE FICHIER (persistante entre mises à jour) ─────────────────
const dataFile = path.join(app.getPath('userData'), 'dd-timer-data.json');
ipcMain.handle('load-data', () => {
try {
if (fs.existsSync(dataFile)) return fs.readFileSync(dataFile, 'utf-8');
} catch (e) { console.error('load-data error:', e.message); }
return null;
});
ipcMain.on('save-data', (event, json) => {
try {
fs.writeFileSync(dataFile, json, 'utf-8');
} catch (e) { console.error('save-data error:', e.message); }
});
// ─── NTFY (notifications mobiles) ───────────────────────────────────────── // ─── NTFY (notifications mobiles) ─────────────────────────────────────────
ipcMain.on('send-ntfy', (event, { url, title, message }) => { ipcMain.on('send-ntfy', (event, { url, title, message }) => {
if (!url) return; if (!url) return;
@ -343,8 +368,8 @@ function launchUpdater(newExe, currentExe) {
const batContent = [ const batContent = [
'@echo off', '@echo off',
'timeout /t 3 /nobreak >nul', 'timeout /t 3 /nobreak >nul',
`"${newExe}" /S`, `start /wait "" "${newExe}" /S`,
'timeout /t 2 /nobreak >nul', 'timeout /t 5 /nobreak >nul',
`start "" "${currentExe}"`, `start "" "${currentExe}"`,
'del "%~f0"', 'del "%~f0"',
].join('\r\n'); ].join('\r\n');

View File

@ -1,6 +1,6 @@
{ {
"name": "minuteur-dragodinde", "name": "minuteur-dragodinde",
"version": "1.1.1", "version": "1.1.2",
"description": "Minuteur elevage Dragodinde Dofus 3", "description": "Minuteur elevage Dragodinde Dofus 3",
"main": "main.js", "main": "main.js",
"author": "Mickael", "author": "Mickael",

View File

@ -3,6 +3,10 @@ const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', { contextBridge.exposeInMainWorld('electronAPI', {
isElectron: true, isElectron: true,
// Sauvegarde persistante (fichier JSON dans userData)
saveData: (json) => ipcRenderer.send('save-data', json),
loadData: () => ipcRenderer.invoke('load-data'),
// Alarme // Alarme
triggerAlarm: (enclosName) => ipcRenderer.send('trigger-alarm', { enclosName }), triggerAlarm: (enclosName) => ipcRenderer.send('trigger-alarm', { enclosName }),
showNotification: (title, body) => ipcRenderer.send('show-notification', { title, body }), showNotification: (title, body) => ipcRenderer.send('show-notification', { title, body }),

View File

@ -1052,12 +1052,18 @@ function save(){
try{ try{
const d=JSON.parse(JSON.stringify(S)); const d=JSON.parse(JSON.stringify(S));
d.enclos.forEach(e=>{e.timer.running=false;e.alerted={};}); d.enclos.forEach(e=>{e.timer.running=false;e.alerted={};});
localStorage.setItem('dd3v3',JSON.stringify(d)); const json=JSON.stringify(d);
// Sauvegarde fichier (persistante) + localStorage (fallback)
if(window.electronAPI?.saveData) window.electronAPI.saveData(json);
localStorage.setItem('dd3v3',json);
}catch(e){} }catch(e){}
} }
function load(){ async function load(){
try{ try{
const raw=localStorage.getItem('dd3v3')||localStorage.getItem('dd3v2'); // Priorité : fichier persistant > localStorage
let raw=null;
if(window.electronAPI?.loadData) raw=await window.electronAPI.loadData();
if(!raw) raw=localStorage.getItem('dd3v3')||localStorage.getItem('dd3v2');
if(!raw)return; if(!raw)return;
const d=JSON.parse(raw); const d=JSON.parse(raw);
S.enclos=d.enclos||[];S.activeId=d.activeId;S.nextEnclosId=d.nextEnclosId||1; S.enclos=d.enclos||[];S.activeId=d.activeId;S.nextEnclosId=d.nextEnclosId||1;
@ -2262,12 +2268,14 @@ if(window.electronAPI?.isElectron){
// ══════════════════════════════════════════ // ══════════════════════════════════════════
// INIT // INIT
// ══════════════════════════════════════════ // ══════════════════════════════════════════
load(); (async()=>{
if(!S.enclos.length){const e=makeEnclos(S.nextEnclosId++);S.enclos.push(e);S.activeId=e.id;} await load();
notifGranted=typeof Notification!=='undefined'&&Notification.permission==='granted'; if(!S.enclos.length){const e=makeEnclos(S.nextEnclosId++);S.enclos.push(e);S.activeId=e.id;}
render(); notifGranted=typeof Notification!=='undefined'&&Notification.permission==='granted';
if(activeEnclos()?.dragodindes.length===0)addDD(S.activeId); render();
requestAnimationFrame(loop); if(activeEnclos()?.dragodindes.length===0)addDD(S.activeId);
requestAnimationFrame(loop);
})();
</script> </script>
</body> </body>
</html> </html>