feat: add resumability detection and pause warnings

- Update 'fetch_metadata' to detect 'Accept-Ranges' HTTP header
- Persist 'resumable' flag in DownloadItem across backend and frontend
- Add confirmation dialog when pausing non-resumable downloads (single and bulk actions)
- Improve UI for start/pause/options buttons by adopting the application accent color on hover
This commit is contained in:
NimBold
2026-06-28 00:03:12 +03:30
parent 1cba5ee556
commit 77b940df60
10 changed files with 63 additions and 7 deletions
+3 -1
View File
@@ -264,7 +264,8 @@ export const AddDownloadsModal = () => {
),
size: meta.size_bytes ? meta.size : undefined,
sizeBytes: meta.size_bytes || undefined,
status: 'ready'
status: 'ready',
resumable: meta.resumable
})
));
}
@@ -617,6 +618,7 @@ export const AddDownloadsModal = () => {
? finalLocation
: destinationOverrides[itemIndex],
isMedia: item.isMedia,
resumable: item.resumable,
mediaFormatSelector: formatSelector,
size: item.size || (item.sizeBytes ? formatBytes(item.sizeBytes) : undefined)
}, action);
+1 -1
View File
@@ -12,7 +12,7 @@ interface DownloadItemProps {
index: number;
tableGridTemplate: string;
setContextMenu: (menu: { x: number; y: number; id: string }) => void;
handlePause: (id: string) => void;
handlePause: (id: string, skipConfirm?: boolean) => void;
handleResume: (item: DownloadItemType) => void;
getCategoryIcon: (category: string) => React.ReactNode;
isSelected: boolean;
+23 -2
View File
@@ -255,7 +255,15 @@ export const DownloadTable: React.FC<DownloadTableProps> = ({ filter }) => {
}
};
const handlePause = async (id: string) => {
const handlePause = async (id: string, skipConfirm = false) => {
const download = useDownloadStore.getState().downloads.find(d => d.id === id);
if (!skipConfirm && download && download.resumable === false) {
const confirmPause = window.confirm("This download does not support resuming. If you pause it, you will have to start over again later. Are you sure you want to pause?");
if (!confirmPause) {
return;
}
}
try {
await invoke('pause_download', { id });
} catch (e) {
@@ -324,7 +332,20 @@ export const DownloadTable: React.FC<DownloadTableProps> = ({ filter }) => {
className="main-control-button"
disabled={sortedDownloads.length === 0}
onClick={() => {
sortedDownloads.filter(d => canPauseDownload(d.status)).forEach(d => handlePause(d.id));
const toPause = sortedDownloads.filter(d => canPauseDownload(d.status));
const nonResumableCount = toPause.filter(d => d.resumable === false).length;
if (nonResumableCount > 0) {
const confirmPause = window.confirm(
nonResumableCount === 1
? "1 download does not support resuming. If you pause it, you will have to start over again later. Are you sure you want to pause?"
: `${nonResumableCount} downloads do not support resuming. If you pause them, you will have to start over again later. Are you sure you want to pause?`
);
if (!confirmPause) {
return;
}
}
// Skip the individual check by passing a flag to handlePause, or just invoking directly.
toPause.forEach(d => handlePause(d.id, true));
}}
title="Pause All"
>