diff --git a/src/components/DownloadItem.tsx b/src/components/DownloadItem.tsx index e28c91f..7028ba4 100644 --- a/src/components/DownloadItem.tsx +++ b/src/components/DownloadItem.tsx @@ -5,6 +5,7 @@ import { useDownloadProgressStore } from '../store/downloadStore'; import { Play, Pause, MoreVertical, Clock, ArrowUp, ArrowDown } from 'lucide-react'; import type { DownloadItem as DownloadItemType } from '../bindings/DownloadItem'; import { canPauseDownload, canStartDownload, startActionLabel } from '../utils/downloadActions'; +import { isActiveDownloadStatus } from '../utils/downloads'; interface DownloadItemProps { downloadId: string; @@ -37,7 +38,8 @@ export const DownloadItem = React.memo(({ return state.downloads .filter(candidate => candidate.queueId === queueId && - candidate.status !== 'completed' + candidate.status !== 'completed' && + !(isActiveDownloadStatus(candidate.status) && candidate.status !== 'queued') ) .sort((left, right) => (left.queuePosition ?? 0) - (right.queuePosition ?? 0)) .map(candidate => candidate.id); diff --git a/src/components/DownloadTable.tsx b/src/components/DownloadTable.tsx index 38686d9..865e98c 100644 --- a/src/components/DownloadTable.tsx +++ b/src/components/DownloadTable.tsx @@ -16,6 +16,7 @@ import { canStartDownload, startActionLabel } from '../utils/downloadActions'; +import { isActiveDownloadStatus } from '../utils/downloads'; interface DownloadTableProps { filter: SidebarFilter; @@ -186,7 +187,15 @@ export const DownloadTable: React.FC = ({ filter }) => { // Sort by queue position when viewing a specific queue so the visual // order matches the queue order and move-up/down buttons reflect reality. const sortedDownloads = filter.startsWith('queue:') - ? [...filteredDownloads].sort((left, right) => (left.queuePosition ?? 0) - (right.queuePosition ?? 0)) + ? [...filteredDownloads].sort((left, right) => { + const leftActive = isActiveDownloadStatus(left.status) && left.status !== 'queued'; + const rightActive = isActiveDownloadStatus(right.status) && right.status !== 'queued'; + + if (leftActive && !rightActive) return -1; + if (!leftActive && rightActive) return 1; + + return (left.queuePosition ?? 0) - (right.queuePosition ?? 0); + }) : filteredDownloads; const handleItemClick = (e: React.MouseEvent, item: DownloadItem) => { if (e.detail === 2) { diff --git a/src/store/useDownloadStore.ts b/src/store/useDownloadStore.ts index 97abb45..caf4758 100644 --- a/src/store/useDownloadStore.ts +++ b/src/store/useDownloadStore.ts @@ -227,7 +227,11 @@ export const useDownloadStore = create((set, get) => ({ if (!item) return; const queueId = item.queueId || MAIN_QUEUE_ID; const queueItems = get().downloads - .filter(download => (download.queueId || MAIN_QUEUE_ID) === queueId && download.status !== 'completed') + .filter(download => + (download.queueId || MAIN_QUEUE_ID) === queueId && + download.status !== 'completed' && + !(isActiveDownloadStatus(download.status) && download.status !== 'queued') + ) .sort((left, right) => (left.queuePosition ?? 0) - (right.queuePosition ?? 0)); const index = queueItems.findIndex(download => download.id === id); const target = direction === 'up' ? index - 1 : index + 1; @@ -324,9 +328,11 @@ export const useDownloadStore = create((set, get) => ({ const settings = useSettingsStore.getState(); const destPath = await effectiveDestinationForItem(item, settings); const queueId = action.type === 'add-to-queue' ? action.queueId : MAIN_QUEUE_ID; - const queuePosition = get().downloads.filter(download => - (download.queueId || MAIN_QUEUE_ID) === queueId && download.status !== 'completed' - ).length; + const queueItems = get().downloads.filter(download => + (download.queueId || MAIN_QUEUE_ID) === queueId + ); + const maxPos = queueItems.reduce((max, d) => Math.max(max, d.queuePosition ?? 0), -1); + const queuePosition = maxPos + 1; const ownedItem: DownloadItem = { ...item, destination: destPath, @@ -484,7 +490,17 @@ export const useDownloadStore = create((set, get) => ({ } const prevStatus = targetItem.status; - get().updateDownload(id, { status: 'queued', speed: '-', eta: '-' }); + const queueItems = get().downloads.filter(d => + (d.queueId || MAIN_QUEUE_ID) === (targetItem.queueId || MAIN_QUEUE_ID) + ); + const maxPos = queueItems.reduce((max, d) => Math.max(max, d.queuePosition ?? 0), -1); + + get().updateDownload(id, { + status: 'queued', + speed: '-', + eta: '-', + queuePosition: maxPos + 1 + }); const resumedExisting = await invoke('resume_download', { id }).catch(() => false); @@ -608,11 +624,12 @@ export const useDownloadStore = create((set, get) => ({ get().unregisterBackendIds([item.id]); } - const nextPosition = get().downloads.filter(item => + const queueItems = get().downloads.filter(item => !selectedIds.has(item.id) && - (item.queueId || MAIN_QUEUE_ID) === queueId && - item.status !== 'completed' - ).length; + (item.queueId || MAIN_QUEUE_ID) === queueId + ); + const maxPos = queueItems.reduce((max, d) => Math.max(max, d.queuePosition ?? 0), -1); + const nextPosition = maxPos + 1; set(state => ({ downloads: state.downloads.map(item => selectedIds.has(item.id) && item.status !== 'completed' @@ -693,7 +710,9 @@ export const useDownloadStore = create((set, get) => ({ })); // Auto resume downloads that were active or queued - const active = get().downloads.filter(d => d.status === 'queued'); + const active = get().downloads + .filter(d => d.status === 'queued') + .sort((a, b) => (a.queuePosition ?? 0) - (b.queuePosition ?? 0)); if (active.length > 0) { try { const settings = useSettingsStore.getState();