diff --git a/src/manifest.json b/src/manifest.json index 6a45a3c..6f2e429 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -22,7 +22,8 @@ "storage", "alarms", "notifications", - "contextMenus" + "contextMenus", + "downloads" ], "host_permissions": [ "https://www.googleapis.com/*", diff --git a/src/popup/actions.js b/src/popup/actions.js index 68dee33..73532f3 100644 --- a/src/popup/actions.js +++ b/src/popup/actions.js @@ -81,13 +81,15 @@ export async function downloadAttachment(accountId, messageId, attachment) { } const blob = new Blob([bytes], { type: attachment.mimeType || 'application/octet-stream' }); const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = attachment.filename || 'attachment'; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - setTimeout(() => URL.revokeObjectURL(url), 1000); + try { + await api.downloads.download({ + url, + filename: attachment.filename || 'attachment', + saveAs: false, + }); + } finally { + setTimeout(() => URL.revokeObjectURL(url), 5000); + } } export async function bulkAction(action) { diff --git a/src/popup/detail.js b/src/popup/detail.js index ae65148..72db713 100644 --- a/src/popup/detail.js +++ b/src/popup/detail.js @@ -59,10 +59,12 @@ function buildAttachmentItem(accountId, messageId, att) { item.addEventListener('click', async () => { item.disabled = true; + item.classList.remove('attachment-item--error'); try { await downloadAttachment(accountId, messageId, att); - } catch { - // Silently fail — the file icon just stays enabled on next click. + } catch (err) { + console.error('Attachment download failed:', err); + item.classList.add('attachment-item--error'); } finally { item.disabled = false; } diff --git a/src/popup/popup.css b/src/popup/popup.css index 5cfced3..2050a2c 100644 --- a/src/popup/popup.css +++ b/src/popup/popup.css @@ -699,6 +699,11 @@ body { cursor: wait; } +.attachment-item--error { + border-color: var(--danger); + color: var(--danger); +} + .attachment-icon { color: var(--text-secondary); flex-shrink: 0;