desktop v0.1.20 + web: notify on download complete (was silent) (batch135)

Suppressing the save dialog made downloads completely silent — "nothing happened" even though
the file saved to Downloads. Now on download 'done': (1) tell the web UI → branded toast
"Saved X to your Downloads folder" when the window is focused; (2) native OS notification
(click → reveal in Explorer) when the app is minimized/in the tray, so it's never double-noticed;
(3) a failure notice. preload exposes onDownloadDone; home.html shows the toast.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 16:03:24 +05:30
parent 30eaf37773
commit f2b965bd3d
4 changed files with 25 additions and 2 deletions
+18
View File
@@ -465,6 +465,24 @@ function configureSession() {
let target = path.join(dir, name), n = 1;
while (fs.existsSync(target)) target = path.join(dir, `${base} (${n++})${ext}`);
item.setSavePath(target);
// Since we suppressed the save dialog, the download would otherwise be completely silent. Give feedback
// when it finishes: a notification (click → reveal the file in Explorer) so the user knows it saved and
// where. Also tell the web UI so it can show its own toast. On failure, say so.
item.once('done', (_ev, state) => {
try {
const ok = state === 'completed';
const savedName = ok ? path.basename(target) : (item.getFilename() || 'file');
// Always tell the web UI (it shows a branded toast when the window is up).
try { if (win && !win.isDestroyed()) win.webContents.send('download-done', { name: savedName, path: ok ? target : '', ok }); } catch (_) {}
// If the window is focused, that toast is enough — skip the native notification to avoid a double
// notice. If the app is minimized/in the tray, show a native notification instead (click → reveal).
const focused = win && !win.isDestroyed() && win.isVisible() && win.isFocused();
if (!focused && Notification.isSupported()) {
if (ok) { const note = new Notification({ title: 'Download complete', body: savedName + ' — saved to your Downloads folder. Click to show it.' }); note.on('click', () => { try { shell.showItemInFolder(target); } catch (_) {} }); note.show(); }
else new Notification({ title: 'Download failed', body: savedName + ' could not be saved.' }).show();
}
} catch (_) {}
});
} catch (_) {}
});
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "biz-connect-desktop",
"version": "0.1.19",
"version": "0.1.20",
"description": "Biz Connect technician desktop client — loads the Connect web UI with native screen capture",
"author": {
"name": "BizGaze",
+1
View File
@@ -43,5 +43,6 @@ contextBridge.exposeInMainWorld('bizConnectNative', Object.freeze({
// #3: subscribe to auto-update lifecycle events so the UI can show download progress + "ready".
// cb receives {phase:'checking'|'available'|'downloading'|'ready'|'current'|'error', percent?, version?}.
onUpdateEvent: (cb) => { try { ipcRenderer.on('update-event', (_e, data) => { try { cb(data); } catch (_) {} }); } catch (_) {} },
onDownloadDone: (cb) => { try { ipcRenderer.on('download-done', (_e, data) => { try { cb(data); } catch (_) {} }); } catch (_) {} }, // desktop: a file finished downloading to the Downloads folder → show a toast
restartToUpdate: () => ipcRenderer.invoke('restart-to-update'),
}));
+5 -1
View File
@@ -1158,7 +1158,7 @@
</head>
<body>
<script src="/icons.js?v=6"></script>
<script>window.__BUILD='2026-07-19-batch134';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
<script>window.__BUILD='2026-07-19-batch135';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
// Emoji are rendered with the OS's own (colour) emoji font — instant, zero network.
//
// We used to run Twemoji over every emoji, which swapped each one for an <img> pulled INDIVIDUALLY from
@@ -3408,6 +3408,10 @@ function wireUpdateBanner(){
else if(d.phase==='ready'){ ensure().innerHTML=ic('check',15)+' <span>Update ready</span> <button id="updRestart">Restart now</button>'; el.classList.add('show','ready'); const b=el.querySelector('#updRestart'); if(b) b.onclick=()=>{ try{ n.restartToUpdate&&n.restartToUpdate(); }catch(_){} }; }
else if(d.phase==='current'||d.phase==='error'){ if(el){ el.classList.remove('show'); setTimeout(()=>{ if(el&&!el.classList.contains('show')) el.remove(); }, 400); } }
});
// Desktop: a download finished (saved straight to the Downloads folder, no dialog) → confirm with a toast
// so it never feels like "nothing happened". The native app also shows a click-to-reveal OS notification
// when its window isn't focused.
if(n.onDownloadDone) n.onDownloadDone((d)=>{ if(!d) return; toast(d.ok ? ('Saved “'+(d.name||'file')+'” to your Downloads folder') : ('Couldnt download '+(d.name||'the file'))); });
}
// ---- New-web-build detection ----------------------------------------------------------------
// The desktop app closes to TRAY, so it can stay open for weeks and keep running the page it loaded on